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