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 = 
00079                     edge.degenerate? edgeData->triangles[edge.triIndex[0]] : edgeData->triangles[edge.triIndex[1]];
00080                 if (t1.lightFacing && (edge.degenerate || !t2.lightFacing))
00081                 {
00082                     /* Silhouette edge, first tri facing the light
00083                     Also covers degenerate tris where only tri 1 is valid
00084                     Remember verts run anticlockwise along the edge from 
00085                     tri 0 so to point shadow volume tris outward, light cap 
00086                     indexes have to be backwards
00087 
00088                     We emit 2 tris if light is a point light, 1 if light 
00089                     is directional, because directional lights cause all
00090                     points to converge to a single point at infinity.
00091 
00092                     First side tri = near1, near0, far0
00093                     Second tri = far0, far1, near1
00094 
00095                     'far' indexes are 'near' index + originalVertexCount
00096                     because 'far' verts are in the second half of the 
00097                     buffer
00098                     */
00099                     *pIdx++ = edge.vertIndex[1];
00100                     *pIdx++ = edge.vertIndex[0];
00101                     *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00102                     shadOp->indexData->indexCount += 3;
00103 
00104                     // Are we extruding to infinity?
00105                     if (!(lightType == Light::LT_DIRECTIONAL &&
00106                         flags & SRF_EXTRUDE_TO_INFINITY))
00107                     {
00108                         // additional tri to make quad
00109                         *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00110                         *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00111                         *pIdx++ = edge.vertIndex[1];
00112                         shadOp->indexData->indexCount += 3;
00113                     }
00114                     // Do dark cap tri
00115                     // Use McGuire et al method, a triangle fan covering all silhouette
00116                     // edges and one point (taken from the initial tri)
00117                     if (flags & SRF_INCLUDE_DARK_CAP)
00118                     {
00119                         if (firstDarkCapTri)
00120                         {
00121                             darkCapStart = edge.vertIndex[0] + originalVertexCount;
00122                             firstDarkCapTri = false;
00123                         }
00124                         else
00125                         {
00126                             *pIdx++ = darkCapStart;
00127                             *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00128                             *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00129                             shadOp->indexData->indexCount += 3;
00130                         }
00131 
00132                     }
00133                 }
00134                 else if (!t1.lightFacing && (edge.degenerate || t2.lightFacing))
00135                 {
00136                     // Silhouette edge, second tri facing the light
00137                     // Note edge indexes inverse of when t1 is light facing 
00138                     *pIdx++ = edge.vertIndex[0];
00139                     *pIdx++ = edge.vertIndex[1];
00140                     *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00141                     shadOp->indexData->indexCount += 3;
00142 
00143                     // Are we extruding to infinity?
00144                     if (!(lightType == Light::LT_DIRECTIONAL &&
00145                         flags & SRF_EXTRUDE_TO_INFINITY))
00146                     {
00147                         // additional tri to make quad
00148                         *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00149                         *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00150                         *pIdx++ = edge.vertIndex[0];
00151                         shadOp->indexData->indexCount += 3;
00152                     }
00153                     // Do dark cap tri
00154                     // Use McGuire et al method, a triangle fan covering all silhouette
00155                     // edges and one point (taken from the initial tri)
00156                     if (flags & SRF_INCLUDE_DARK_CAP)
00157                     {
00158                         if (firstDarkCapTri)
00159                         {
00160                             darkCapStart = edge.vertIndex[1] + originalVertexCount;
00161                             firstDarkCapTri = false;
00162                         }
00163                         else
00164                         {
00165                             *pIdx++ = darkCapStart;
00166                             *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00167                             *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00168                             shadOp->indexData->indexCount += 3;
00169                         }
00170 
00171                     }
00172                 }
00173 
00174             }
00175 
00176             // Do light cap
00177             if (flags & SRF_INCLUDE_LIGHT_CAP) 
00178             {
00179                 ShadowRenderable* lightCapRend = 0;
00180 
00181                 if ((*si)->isLightCapSeparate())
00182                 {
00183                     // separate light cap
00184                     lightCapRend = (*si)->getLightCapRenderable();
00185                     lightShadOp = lightCapRend->getRenderOperationForUpdate();
00186                     lightShadOp->indexData->indexCount = 0;
00187                     // start indexes after the current total
00188                     // NB we don't update the total here since that's done below
00189                     lightShadOp->indexData->indexStart = 
00190                         indexStart + shadOp->indexData->indexCount;
00191                 }
00192 
00193                 EdgeData::TriangleList::iterator ti, tiend;
00194                 tiend = edgeData->triangles.end();
00195                 for (ti = edgeData->triangles.begin(); ti != tiend; ++ti)
00196                 {
00197                     EdgeData::Triangle& t = *ti;
00198                     // Light facing, and vertex set matches
00199                     if (t.lightFacing && t.vertexSet == eg.vertexSet)
00200                     {
00201                         *pIdx++ = t.vertIndex[0];
00202                         *pIdx++ = t.vertIndex[1];
00203                         *pIdx++ = t.vertIndex[2];
00204                         if (lightShadOp)
00205                         {
00206                             lightShadOp->indexData->indexCount += 3;
00207                         }
00208                         else
00209                         {
00210                             shadOp->indexData->indexCount += 3;
00211                         }
00212                     }
00213                 }
00214 
00215             }
00216             // update next indexStart (all renderables sharing the buffer)
00217             indexStart += shadOp->indexData->indexCount;
00218             // Add on the light cap too
00219             if (lightShadOp)
00220                 indexStart += lightShadOp->indexData->indexCount;
00221 
00222 
00223         }
00224 
00225 
00226         // Unlock index buffer
00227         indexBuffer->unlock();
00228 
00229         // In debug mode, check we didn't overrun the index buffer
00230         assert(indexStart <= indexBuffer->getNumIndexes() &&
00231             "Index buffer overrun while generating shadow volume!! "
00232             "You must increase the size of the shadow index buffer.");
00233 
00234     }
00235     // ------------------------------------------------------------------------
00236     void ShadowCaster::extrudeVertices(
00237         HardwareVertexBufferSharedPtr vertexBuffer, 
00238         size_t originalVertexCount, const Vector4& light, Real extrudeDist)
00239     {
00240         assert (vertexBuffer->getVertexSize() == sizeof(Real) * 3
00241             && "Position buffer should contain only positions!");
00242 
00243         // Extrude the first area of the buffer into the second area
00244         // Lock the entire buffer for writing, even though we'll only be
00245         // updating the latter because you can't have 2 locks on the same
00246         // buffer
00247         Real* pSrc = static_cast<Real*>(
00248             vertexBuffer->lock(HardwareBuffer::HBL_NORMAL));
00249 
00250         Real* pDest = pSrc + originalVertexCount * 3;
00251         // Assume directional light, extrusion is along light direction
00252         Vector3 extrusionDir(-light.x, -light.y, -light.z);
00253         extrusionDir.normalise();
00254         extrusionDir *= extrudeDist;
00255         for (size_t vert = 0; vert < originalVertexCount; ++vert)
00256         {
00257             if (light.w != 0.0f)
00258             {
00259                 // Point light, adjust extrusionDir
00260                 extrusionDir.x = pSrc[0] - light.x;
00261                 extrusionDir.y = pSrc[1] - light.y;
00262                 extrusionDir.z = pSrc[2] - light.z;
00263                 extrusionDir.normalise();
00264                 extrusionDir *= extrudeDist;
00265             }
00266             *pDest++ = *pSrc++ + extrusionDir.x;
00267             *pDest++ = *pSrc++ + extrusionDir.y;
00268             *pDest++ = *pSrc++ + extrusionDir.z;
00269 
00270         }
00271         vertexBuffer->unlock();
00272 
00273     }
00274     // ------------------------------------------------------------------------
00275     void ShadowCaster::extrudeBounds(AxisAlignedBox& box, const Vector4& light, Real extrudeDist) const
00276     {
00277         Vector3 extrusionDir;
00278 
00279         if (light.w == 0)
00280         {
00281             // Parallel projection guarantees min/max relationship remains the same
00282             extrusionDir.x = -light.x;
00283             extrusionDir.y = -light.y;
00284             extrusionDir.z = -light.z;
00285             extrusionDir.normalise();
00286             extrusionDir *= extrudeDist;
00287             box.setExtents(box.getMinimum() + extrusionDir, 
00288                 box.getMaximum() + extrusionDir);
00289         }
00290         else
00291         {
00292             const Vector3* corners = box.getAllCorners();
00293             Vector3 vmin, vmax;
00294 
00295             for (unsigned short i = 0; i < 8; ++i)
00296             {
00297                 extrusionDir.x = corners[i].x - light.x;
00298                 extrusionDir.y = corners[i].y - light.y;
00299                 extrusionDir.z = corners[i].z - light.z;
00300                 extrusionDir.normalise();
00301                 extrusionDir *= extrudeDist;
00302                 Vector3 res = corners[i] + extrusionDir;
00303                 if (i == 0)
00304                 {
00305                     vmin = res;
00306                     vmax = res;
00307                 }
00308                 else
00309                 {
00310                     vmin.makeFloor(res);
00311                     vmax.makeCeil(res);
00312                 }
00313             }
00314 
00315             box.setExtents(vmin, vmax);
00316 
00317         }
00318 
00319     }
00320     // ------------------------------------------------------------------------
00321     Real ShadowCaster::getExtrusionDistance(const Vector3& objectPos, const Light* light) const
00322     {
00323         Vector3 diff = objectPos - light->getDerivedPosition();
00324         return light->getAttenuationRange() - diff.length();
00325     }
00326 
00327 }

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:46 2004