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