public void Draw(DrawState state) { SetupShadowShader(state); //set render mode to shadow map state.PushDrawFlag(new ModelInstance.ShaderProviderFlag(this.shaderProvider)); state.PushDrawFlag(TutorialRenderMode.DrawShadow); //Push the shadow map camera as a post-culler. //This way, anything not within the frustum of the shadow map //camera will not be drawn with the shadow shader state.PushPostCuller(this.shadowMapTarget.Camera); //set an additive blending mode state.PushRenderState(); state.RenderState.AlphaBlend = AlphaBlendState.Additive; state.RenderState.DepthColourCull.DepthWriteEnabled = false; //draw the shadowed scene scene.Draw(state); state.PopRenderState(); state.PopPostCuller(); state.PopDrawFlag <TutorialRenderMode>(); state.PopDrawFlag <ModelInstance.ShaderProviderFlag>(); }
/// <summary> /// Begin the modifier (This method is called by the DrawTarget) /// </summary> /// <param name="state"></param> public void Begin(DrawState state) { enabledBuffer = enabled; spheres.Clear(); cubes.Clear(); if (enabledBuffer) { state.PushPostCuller(this); } }
/// <summary> /// Draw the items in sorted order /// </summary> /// <param name="state"></param> public void Draw(DrawState state) { if (itemCount == 0) { return; } sortFrameIndex++; //sortEvery so many frames... if (sortFrameIndex > sortEvery) { sortFrameIndex = 0; // ok, time to sort } else { //otherwise, //draw using the previous frame sorting... if (sortMode == DepthSortMode.FrontToBack) { for (int i = 0; i < previousFrameVisibleCount; i++) { IDraw item = items[i].item; if (item.CullTest(state)) { item.Draw(state); } } } else { for (int i = previousFrameVisibleCount - 1; i >= 0; i--) { IDraw item = items[i].item; if (item.CullTest(state)) { item.Draw(state); } } } int drawn = 0; //draw the rest... for (int i = previousFrameVisibleCount; i < this.itemCount; i++) { IDraw item = items[i].item; if (item.CullTest(state)) { item.Draw(state); drawn++; } } return; } //sort and draw... ICuller culler = state; state.PushPostCuller(postCuller); postCuller.BeginPreCullItem(state); int index = 0; int visible = 0; int backIndex = itemCount - 1; int backIndexCulled = itemCount - 1; int unsortedItems = 0; Vector3 position, camera, direction; state.Camera.GetCameraPosition(out camera); state.Camera.GetCameraViewDirection(out direction); for (int i = 0; i < itemCount; i++) { Entry item = items[index]; postCuller.ResetPreCullItem(); bool cullTest = item.item.CullTest(culler); if (cullTest && postCuller.TryGetPosition(out position)) { //keep item in the list items[index] = items[visible]; //centre of cull tests position.X -= camera.X; position.Y -= camera.Y; position.Z -= camera.Z; float depth = direction.X * position.X + direction.Y * position.Y + direction.Z * position.Z; if (depth > 0) { depth = position.X * position.X + position.Y * position.Y + position.Z * position.Z; } depths[visible] = depth; items[visible] = item; visible++; index++; } else { //swap the back culled element to this one, don't increment index items[index] = items[backIndexCulled]; items[backIndexCulled] = item; backIndexCulled--; if (cullTest) { //as the last step, put this item at the very back. items[backIndexCulled + 1] = items[backIndex]; items[backIndex] = item; depths[backIndex] = item.addIndex; backIndex--; unsortedItems++; } } } state.PopPostCuller(); if (unsortedItems > 0) { backIndex++; //due to the way the algorithm works, the unsorted list is usually ordered like so: //1,2,3,4,5,6,7,0 //so put the last element first, and check if they are out of order float lastD = this.depths[this.itemCount - 1]; Entry lastE = this.items[this.itemCount - 1]; bool outOfOrder = lastD > this.depths[backIndex]; for (int i = this.itemCount - 2; i >= backIndex; i--) { if (i != this.itemCount - 2) { outOfOrder |= this.depths[i] > this.depths[i + 1]; } this.items[i + 1] = this.items[i]; this.depths[i + 1] = this.depths[i]; } this.depths[backIndex] = lastD; this.items[backIndex] = lastE; //draw the unsorted items in their add order (which was written to depths) //this sort won't be all that efficient if (outOfOrder) { Array.Sort(this.depths, this.items, backIndex, unsortedItems); } for (int i = 0; i < unsortedItems; i++) { items[backIndex++].item.Draw(state); } } if (visible > 0) { //if the frame hasn't changed, the items should already be in sorted order, //so this sort should be quick //test if the values are already sorted... float depth = this.depths[0]; bool outOfOrder = false; for (int i = 1; i < visible; i++) { outOfOrder |= depths[i] < depth; depth = depths[i]; } if (outOfOrder) { Array.Sort(this.depths, this.items, 0, visible); } if (sortMode == DepthSortMode.FrontToBack) { for (int i = 0; i < visible; i++) { items[i].item.Draw(state); } } else { for (int i = visible - 1; i >= 0; i--) { items[i].item.Draw(state); } } } previousFrameVisibleCount = visible; }