public Region(StaticGeometry parent, string name, SceneManager mgr, UInt32 regionID, Vector3 center) { this.parent = parent; this.name = name; this.sceneMgr = mgr; this.regionID = regionID; this.center = center; queuedSubMeshes = new List <QueuedSubMesh>(); lodSquaredDistances = new List <float>(); aabb = new AxisAlignedBox(); lodBucketList = new List <LODBucket>(); shadowRenderables = new ShadowRenderableList(); }
public Region(StaticGeometry parent, string name, SceneManager mgr, UInt32 regionID, Vector3 center) { this.parent = parent; this.name = name; this.sceneMgr = mgr; this.regionID = regionID; this.center = center; queuedSubMeshes = new List<QueuedSubMesh>(); lodSquaredDistances = new List<float>(); aabb = new AxisAlignedBox(); lodBucketList = new List<LODBucket>(); shadowRenderables = new ShadowRenderableList(); }
public Region(StaticGeometry parent, string name, SceneManager mgr, UInt32 regionID, Vector3 center) : base(name) { MovableType = "StaticGeometry"; this.parent = parent; this.sceneMgr = mgr; this.regionID = regionID; this.center = center; this.queuedSubMeshes = new List <QueuedSubMesh>(); this.lodValues = new LodValueList(); this.aabb = new AxisAlignedBox(); this.lodBucketList = new List <LODBucket>(); this.shadowRenderables = new ShadowRenderableList(); }
/// <summary> /// Generates the indexes required to render a shadow volume into the /// index buffer which is passed in, and updates shadow renderables to use it. /// </summary> /// <param name="edgeData">The edge information to use.</param> /// <param name="indexBuffer">The buffer into which to write data into; current /// contents are assumed to be discardable.</param> /// <param name="light">The light, mainly for type info as silhouette calculations /// should already have been done in <see cref="UpdateEdgeListLightFacing"/></param> /// <param name="shadowRenderables">A list of shadow renderables which has /// already been constructed but will need populating with details of /// the index ranges to be used.</param> /// <param name="flags">Additional controller flags, see <see cref="ShadowRenderableFlags"/>.</param> protected virtual void GenerateShadowVolume( EdgeData edgeData, HardwareIndexBuffer indexBuffer, Light light, ShadowRenderableList shadowRenderables, int flags ) { // Edge groups should be 1:1 with shadow renderables Debug.Assert( edgeData.edgeGroups.Count == shadowRenderables.Count ); LightType lightType = light.Type; bool extrudeToInfinity = ( flags & (int)ShadowRenderableFlags.ExtrudeToInfinity ) > 0; // Lock index buffer for writing IntPtr idxPtr = indexBuffer.Lock( BufferLocking.Discard ); int indexStart = 0; unsafe { // TODO: Will currently cause an overflow for 32 bit indices, revisit short* pIdx = (short*)idxPtr.ToPointer(); int count = 0; // Iterate over the groups and form renderables for each based on their // lightFacing for ( int groupCount = 0; groupCount < edgeData.edgeGroups.Count; groupCount++ ) { EdgeData.EdgeGroup eg = (EdgeData.EdgeGroup)edgeData.edgeGroups[ groupCount ]; ShadowRenderable si = (ShadowRenderable)shadowRenderables[ groupCount ]; RenderOperation lightShadOp = null; // Initialize the index bounds for this shadow renderable RenderOperation shadOp = si.GetRenderOperationForUpdate(); shadOp.indexData.indexCount = 0; shadOp.indexData.indexStart = indexStart; // original number of verts (without extruded copy) int originalVertexCount = eg.vertexData.vertexCount; bool firstDarkCapTri = true; int darkCapStart = 0; for ( int edgeCount = 0; edgeCount < eg.edges.Count; edgeCount++ ) { EdgeData.Edge edge = (EdgeData.Edge)eg.edges[ edgeCount ]; EdgeData.Triangle t1 = (EdgeData.Triangle)edgeData.triangles[ edge.triIndex[ 0 ] ]; EdgeData.Triangle t2 = edge.isDegenerate ? (EdgeData.Triangle)edgeData.triangles[ edge.triIndex[ 0 ] ] : (EdgeData.Triangle)edgeData.triangles[ edge.triIndex[ 1 ] ]; if ( t1.lightFacing && ( edge.isDegenerate || !t2.lightFacing ) ) { /* Silhouette edge, first tri facing the light Also covers degenerate tris where only tri 1 is valid Remember verts run anticlockwise along the edge from tri 0 so to point shadow volume tris outward, light cap indexes have to be backwards We emit 2 tris if light is a point light, 1 if light is directional, because directional lights cause all points to converge to a single point at infinity. First side tri = near1, near0, far0 Second tri = far0, far1, near1 'far' indexes are 'near' index + originalVertexCount because 'far' verts are in the second half of the buffer */ pIdx[ count++ ] = (short)edge.vertIndex[ 1 ]; pIdx[ count++ ] = (short)edge.vertIndex[ 0 ]; pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; if ( !( lightType == LightType.Directional && extrudeToInfinity ) ) { // additional tri to make quad pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); pIdx[ count++ ] = (short)edge.vertIndex[ 1 ]; shadOp.indexData.indexCount += 3; } // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if ( ( flags & (int)ShadowRenderableFlags.IncludeDarkCap ) > 0 ) { if ( firstDarkCapTri ) { darkCapStart = edge.vertIndex[ 0 ] + originalVertexCount; firstDarkCapTri = false; } else { pIdx[ count++ ] = (short)darkCapStart; pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; } } } else if ( !t1.lightFacing && ( edge.isDegenerate || t2.lightFacing ) ) { // Silhouette edge, second tri facing the light // Note edge indexes inverse of when t1 is light facing pIdx[ count++ ] = (short)edge.vertIndex[ 0 ]; pIdx[ count++ ] = (short)edge.vertIndex[ 1 ]; pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; if ( !( lightType == LightType.Directional && extrudeToInfinity ) ) { // additional tri to make quad pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); pIdx[ count++ ] = (short)edge.vertIndex[ 0 ]; shadOp.indexData.indexCount += 3; } // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if ( ( flags & (int)ShadowRenderableFlags.IncludeDarkCap ) > 0 ) { if ( firstDarkCapTri ) { darkCapStart = edge.vertIndex[ 1 ] + originalVertexCount; firstDarkCapTri = false; } else { pIdx[ count++ ] = (short)darkCapStart; pIdx[ count++ ] = (short)( edge.vertIndex[ 0 ] + originalVertexCount ); pIdx[ count++ ] = (short)( edge.vertIndex[ 1 ] + originalVertexCount ); shadOp.indexData.indexCount += 3; } } } } // Do light cap if ( ( flags & (int)ShadowRenderableFlags.IncludeLightCap ) > 0 ) { ShadowRenderable lightCapRend = null; if ( si.IsLightCapSeperate ) { // separate light cap lightCapRend = si.LightCapRenderable; lightShadOp = lightCapRend.GetRenderOperationForUpdate(); lightShadOp.indexData.indexCount = 0; // start indexes after the current total // NB we don't update the total here since that's done below lightShadOp.indexData.indexStart = indexStart + shadOp.indexData.indexCount; } for ( int triCount = 0; triCount < edgeData.triangles.Count; triCount++ ) { EdgeData.Triangle t = (EdgeData.Triangle)edgeData.triangles[ triCount ]; // Light facing, and vertex set matches if ( t.lightFacing && t.vertexSet == eg.vertexSet ) { pIdx[ count++ ] = (short)t.vertIndex[ 0 ]; pIdx[ count++ ] = (short)t.vertIndex[ 1 ]; pIdx[ count++ ] = (short)t.vertIndex[ 2 ]; if ( lightShadOp != null ) { lightShadOp.indexData.indexCount += 3; } else { shadOp.indexData.indexCount += 3; } } } } // update next indexStart (all renderables sharing the buffer) indexStart += shadOp.indexData.indexCount; // add on the light cap too if ( lightShadOp != null ) { indexStart += lightShadOp.indexData.indexCount; } } } // Unlock index buffer indexBuffer.Unlock(); Debug.Assert( indexStart <= indexBuffer.IndexCount, "Index buffer overrun while generating shadow volume!" ); }
/// <summary> /// Generates the indexes required to render a shadow volume into the /// index buffer which is passed in, and updates shadow renderables to use it. /// </summary> /// <param name="edgeData">The edge information to use.</param> /// <param name="indexBuffer">The buffer into which to write data into; current /// contents are assumed to be discardable.</param> /// <param name="light">The light, mainly for type info as silhouette calculations /// should already have been done in <see cref="UpdateEdgeListLightFacing"/></param> /// <param name="shadowRenderables">A list of shadow renderables which has /// already been constructed but will need populating with details of /// the index ranges to be used.</param> /// <param name="flags">Additional controller flags, see <see cref="ShadowRenderableFlags"/>.</param> protected virtual void GenerateShadowVolume(EdgeData edgeData, HardwareIndexBuffer indexBuffer, Light light, ShadowRenderableList shadowRenderables, int flags) { // Edge groups should be 1:1 with shadow renderables Debug.Assert(edgeData.edgeGroups.Count == shadowRenderables.Count); LightType lightType = light.Type; bool extrudeToInfinity = (flags & (int)ShadowRenderableFlags.ExtrudeToInfinity) > 0; // Lock index buffer for writing IntPtr idxPtr = indexBuffer.Lock(BufferLocking.Discard); int indexStart = 0; unsafe { // TODO: Will currently cause an overflow for 32 bit indices, revisit short *pIdx = (short *)idxPtr.ToPointer(); int count = 0; // Iterate over the groups and form renderables for each based on their // lightFacing for (int groupCount = 0; groupCount < edgeData.edgeGroups.Count; groupCount++) { EdgeData.EdgeGroup eg = (EdgeData.EdgeGroup)edgeData.edgeGroups[groupCount]; ShadowRenderable si = (ShadowRenderable)shadowRenderables[groupCount]; RenderOperation lightShadOp = null; // Initialise the index bounds for this shadow renderable RenderOperation shadOp = si.GetRenderOperationForUpdate(); shadOp.indexData.indexCount = 0; shadOp.indexData.indexStart = indexStart; // original number of verts (without extruded copy) int originalVertexCount = eg.vertexData.vertexCount; bool firstDarkCapTri = true; int darkCapStart = 0; for (int edgeCount = 0; edgeCount < eg.edges.Count; edgeCount++) { EdgeData.Edge edge = (EdgeData.Edge)eg.edges[edgeCount]; EdgeData.Triangle t1 = (EdgeData.Triangle)edgeData.triangles[edge.triIndex[0]]; EdgeData.Triangle t2 = edge.isDegenerate ? (EdgeData.Triangle)edgeData.triangles[edge.triIndex[0]] : (EdgeData.Triangle)edgeData.triangles[edge.triIndex[1]]; if (t1.lightFacing && (edge.isDegenerate || !t2.lightFacing)) { /* Silhouette edge, first tri facing the light * Also covers degenerate tris where only tri 1 is valid * Remember verts run anticlockwise along the edge from * tri 0 so to point shadow volume tris outward, light cap * indexes have to be backwards * * We emit 2 tris if light is a point light, 1 if light * is directional, because directional lights cause all * points to converge to a single point at infinity. * * First side tri = near1, near0, far0 * Second tri = far0, far1, near1 * * 'far' indexes are 'near' index + originalVertexCount * because 'far' verts are in the second half of the * buffer */ pIdx[count++] = (short)edge.vertIndex[1]; pIdx[count++] = (short)edge.vertIndex[0]; pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount); shadOp.indexData.indexCount += 3; if (!(lightType == LightType.Directional && extrudeToInfinity)) { // additional tri to make quad pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount); pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount); pIdx[count++] = (short)edge.vertIndex[1]; shadOp.indexData.indexCount += 3; } // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if ((flags & (int)ShadowRenderableFlags.IncludeDarkCap) > 0) { if (firstDarkCapTri) { darkCapStart = edge.vertIndex[0] + originalVertexCount; firstDarkCapTri = false; } else { pIdx[count++] = (short)darkCapStart; pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount); pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount); shadOp.indexData.indexCount += 3; } } } else if (!t1.lightFacing && (edge.isDegenerate || t2.lightFacing)) { // Silhouette edge, second tri facing the light // Note edge indexes inverse of when t1 is light facing pIdx[count++] = (short)edge.vertIndex[0]; pIdx[count++] = (short)edge.vertIndex[1]; pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount); shadOp.indexData.indexCount += 3; if (!(lightType == LightType.Directional && extrudeToInfinity)) { // additional tri to make quad pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount); pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount); pIdx[count++] = (short)edge.vertIndex[0]; shadOp.indexData.indexCount += 3; } // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if ((flags & (int)ShadowRenderableFlags.IncludeDarkCap) > 0) { if (firstDarkCapTri) { darkCapStart = edge.vertIndex[1] + originalVertexCount; firstDarkCapTri = false; } else { pIdx[count++] = (short)darkCapStart; pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount); pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount); shadOp.indexData.indexCount += 3; } } } } // Do light cap if ((flags & (int)ShadowRenderableFlags.IncludeLightCap) > 0) { ShadowRenderable lightCapRend = null; if (si.IsLightCapSeperate) { // separate light cap lightCapRend = si.LightCapRenderable; lightShadOp = lightCapRend.GetRenderOperationForUpdate(); lightShadOp.indexData.indexCount = 0; // start indexes after the current total // NB we don't update the total here since that's done below lightShadOp.indexData.indexStart = indexStart + shadOp.indexData.indexCount; } for (int triCount = 0; triCount < edgeData.triangles.Count; triCount++) { EdgeData.Triangle t = (EdgeData.Triangle)edgeData.triangles[triCount]; // Light facing, and vertex set matches if (t.lightFacing && t.vertexSet == eg.vertexSet) { pIdx[count++] = (short)t.vertIndex[0]; pIdx[count++] = (short)t.vertIndex[1]; pIdx[count++] = (short)t.vertIndex[2]; if (lightShadOp != null) { lightShadOp.indexData.indexCount += 3; } else { shadOp.indexData.indexCount += 3; } } } } // update next indexStart (all renderables sharing the buffer) indexStart += shadOp.indexData.indexCount; // add on the light cap too if (lightShadOp != null) { indexStart += lightShadOp.indexData.indexCount; } } } // Unlock index buffer indexBuffer.Unlock(); Debug.Assert(indexStart <= indexBuffer.IndexCount, "Index buffer overrun while generating shadow volume!"); }
public Region( StaticGeometry parent, string name, SceneManager mgr, UInt32 regionID, Vector3 center ) : base( name ) { MovableType = "StaticGeometry"; this.parent = parent; this.sceneMgr = mgr; this.regionID = regionID; this.center = center; this.queuedSubMeshes = new List<QueuedSubMesh>(); this.lodValues = new LodValueList(); this.aabb = new AxisAlignedBox(); this.lodBucketList = new List<LODBucket>(); this.shadowRenderables = new ShadowRenderableList(); }