private bool worldMatrixDirty = true; // set to true if worldMatrix is no longer valid, see 'UpdateWorldMatrix()'

		//create the actor
		public Actor(ContentRegister content, UpdateManager updateManager, MaterialLightCollection lights, float groundRadius)
		{
			this.groundRadius = groundRadius;

			model = new ModelInstance();
			model.LightCollection = lights;

			//force the model to render using spherical harmonic lighting
			//this will significantly improve performance on some hardware when GPU limited
			model.ShaderProvider = new Xen.Ex.Graphics.Provider.LightingDisplayShaderProvider(LightingDisplayModel.ForceSphericalHarmonic, model.ShaderProvider);

			//random starting position
			position = GetRandomPosition();

			//initially target the current position
			//the 'move to next target' timer will wind down and then the actor will move
			target = position;

			//randomize a bit
			lookAngle = (float)random.NextDouble() * MathHelper.TwoPi;
			moveSpeed = (float)random.NextDouble() * 0.9f + 0.1f;

			content.Add(this);
			updateManager.Add(this);


			InitaliseAnimations(updateManager);
		}
		//constructor
		public SphereDrawer(Vector3 position)
		{
			//setup the sphere geometry
			var size = new Vector3(1,1,1);
			//Use the prebuilt sphere geometry class
			this.sphereGeometry = new Sphere(size, 32);

			//Setup the world matrix
			this.worldMatrix = Matrix.CreateTranslation(position);

			//Create a lighting shader with some nice looking lighting
			//'MaterialShader' is a prebuilt class in Xen.Ex. It is similar to the XNA BasicEffect
			//This class implements the IShader interface. All Xen shaders implement IShader.
			this.shader = new MaterialShader();
			this.shader.SpecularColour = Color.LightYellow.ToVector3();						//give the material a nice sheen

			var lightDirection = new Vector3(0.5f,1,-0.5f); //a dramatic direction

			//create a light collection and add a couple of lights to it
			var lights = new MaterialLightCollection();

			lights.AmbientLightColour = Color.CornflowerBlue.ToVector3() * 0.5f;	//set the ambient
			lights.CreateDirectionalLight(lightDirection, Color.Gray);				//add the first of two light sources
			lights.CreateDirectionalLight(-lightDirection, Color.DarkSlateBlue);

			//set the light collection used by the material shader
			this.shader.LightCollection = lights;
		}
		public ObjectComposer AppendMaterialLights(MaterialLightCollection collection = null)
		{
			if (currentObject.Shader == null) throw new Exception("Append shader before customising it!");

			if(collection == null) collection = new MaterialLightCollection();
			currentObject.Shader.LightCollection = collection;
			return this;
		}
		public GroundDisk(ContentRegister content, MaterialLightCollection lights, float radius)
		{
			this.radius = radius;

			int vertexCount = 256;
			var indices = new List<int>();

			//create the vertices. Note the DiskVertex() constructor takes an angle/size
			var verts = new DiskVertex[vertexCount];

			for (int i = 0; i < vertexCount; i++)
			{
				verts[i] = new DiskVertex((i / (float)(vertexCount - 1)) * MathHelper.TwoPi, radius, 0.05f);
				
				if (i != 0)	//add the tirangle indices
				{
					indices.Add(0);
					indices.Add(i - 1);
					indices.Add(i);
				}
			}

			//create the vertex buffer
			this.vertices = new Vertices<DiskVertex>(verts);
			this.indices = new Indices<int>(indices);


			//create the custom material for this geometry
			//the light collection has been passed into the constructor, although it
			//could easily be changed later (by changing material.Lights)
			this.Material = new MaterialShader(lights);
			
			//give the disk really bright specular for effect
			Material.SpecularColour = new Vector3(1,1,1);
			Material.DiffuseColour = new Vector3(0.6f, 0.6f, 0.6f);
			Material.SpecularPower = 64;

			//setup the texture samples to use high quality anisotropic filtering
			//the textures are assigned in LoadContent
			Material.Textures = new MaterialTextures();
			Material.Textures.TextureMapSampler = TextureSamplerState.AnisotropicHighFiltering;
			Material.Textures.NormalMapSampler = TextureSamplerState.AnisotropicLowFiltering;

			//load the textures for this material
			content.Add(this);
		}
Пример #5
0
        public GroundDisk(ContentRegister content, float radius, MaterialLightCollection lights)
        {
            //build the disk
            VertexPositionNormalTexture[] vertexData = new VertexPositionNormalTexture[256];

            for (int i = 0; i < vertexData.Length; i++)
            {
                //a bunch of vertices, in a circle!
                float   angle    = (float)i / (float)vertexData.Length * MathHelper.TwoPi;
                Vector3 position = new Vector3((float)Math.Sin(angle), (float)Math.Cos(angle), 0);

                vertexData[i] = new VertexPositionNormalTexture(position * radius, new Vector3(0, 0, 1), new Vector2(position.X, position.Y));
            }
            this.vertices = new Vertices <VertexPositionNormalTexture>(vertexData);

            //create the material, and add to content
            this.material        = new MaterialShader();
            this.material.Lights = lights;
            content.Add(this);
        }
		//NEW CODE
		public Actor(ContentRegister content, MaterialLightCollection lights)
		{
			//A ModelInstance can be created without any content...
			//However it cannot be used until the content is set

			model = new ModelInstance();
			model.LightCollection = lights;	//this class is reused by later tutorials, which require lights

			//get and create the animation controller for this model.
			animationController = model.GetAnimationController();

			//NOTE: Animations cannot be played until the model data has been loaded...

			content.Add(this);

			//At this point in this tutorial, the model is now loaded.

			//get the index of the walk animation
			//this model has 4 animations, Wave, Jog, Walk and Loiter
			//The animations are stored in model.ModelData.Animations
			int animationIndex = animationController.AnimationIndex("Walk");

			//begin playing the animation, looping
			animation = animationController.PlayLoopingAnimation(animationIndex);

			//as many animations as you want can be played at any one time
			//to blend between animations, adjust their weighting with:
			//animation.Weighting = ...;
			//Combined weightings usually should add up to 1.0
			//A weighting of 0 means the animation has no effect, 1 has normal effect.
			//Values outside the 0-1 range usually produces undesirable results.

			//Note:
			//Animations in xen are lossy compressed.
			//For the model used here, the animation data is reduced from nearly 2mb
			//down to around 200kb. (The model geometry is less than 300kb)
			//The amount of compression change can be configured in the content's properties
			//The 'Animation Compression Tolerance' value is a percentage
			//The default is .5%. This means the animation will always be within .5%
			//of the source. Setting this value to 0 will save a lossless animation.
		}
Пример #7
0
        public GroundDisk(ContentRegister content, MaterialLightCollection lights, float radius)
        {
            this.radius = radius;

            int vertexCount = 256;

            //create the vertices. Note the DiskVertex() constructor takes an angle/size
            DiskVertex[] verts = new DiskVertex[vertexCount];
            for (int i = 0; i < vertexCount; i++)
            {
                verts[i] = new DiskVertex((i / (float)(vertexCount - 1)) * MathHelper.TwoPi, radius, 0.05f);
            }

            //create the vertex buffer
            this.vertices = new Vertices <DiskVertex>(verts);


            //create the custom material for this geometry
            //the light collection has been passed into the constructor, although it
            //could easily be changed later (by changing material.Lights)
            this.material = new MaterialShader(lights);

            //By default, per-pixel lighting in the material shader does not do
            //specular reflection. This is because specular nearly triples the
            //complexity of the lighting calculation - which makes rendering slower
            //and reduces the maximum number of per-pixel lights supported from 4 to 2.
            material.UsePerPixelSpecular = true;

            //give the disk really bright specular for effect
            material.SpecularColour = new Vector3(1, 1, 1);
            material.DiffuseColour  = new Vector3(0.6f, 0.6f, 0.6f);
            material.SpecularPower  = 64;

            //setup the texture samples to use high quality anisotropic filtering
            material.TextureMapSampler = TextureSamplerState.AnisotropicHighFiltering;
            material.NormalMapSampler  = TextureSamplerState.AnisotropicLowFiltering;

            //load the textures for this material
            content.Add(this);
        }
Пример #8
0
        private bool worldMatrixDirty = true;         // set to true if worldMatrix is no longer valid, see 'UpdateWorldMatrix()'

        //create the actor
        public Actor(ContentRegister content, UpdateManager updateManager, MaterialLightCollection lights, float groundRadius)
        {
            this.groundRadius = groundRadius;

            model = new ModelInstance();
            model.LightCollection = lights;

            //random starting position
            position = GetRandomPosition();

            //initially target the current position
            //the 'move to next target' timer will wind down and then the actor will move
            target = position;

            //randomize a bit
            lookAngle = (float)random.NextDouble() * MathHelper.TwoPi;
            moveSpeed = (float)random.NextDouble() * 0.9f + 0.1f;

            content.Add(this);
            updateManager.Add(this);


            InitaliseAnimations(updateManager);
        }
Пример #9
0
        protected override void Initialise()
        {
            camera = new Camera3D();

            //create the draw target.
            drawToScreen = new DrawTargetScreen(this, camera);
            //clear to dark blue
            drawToScreen.ClearBuffer.ClearColour = new Color(20, 20, 40);

            //create the light collection
            lights = new MaterialLightCollection();
            //set a dark blue ambient colour
            lights.AmbientLightColour = new Color(40, 40, 80).ToVector3();

            //positions for two lights
            Vector3[] lightPositions = new Vector3[]
            {
                new Vector3(0, 30, 2),
                new Vector3(0, -30, 2)
            };

            //geometry for a light (shared for each light)
            IDraw lightGeometry = null;

            for (int i = 0; i < lightPositions.Length; i++)
            {
                float lightHalfFalloffDistance = 15;
                Color lightColor          = Color.LightYellow;
                Color lightSpecularColour = Color.WhiteSmoke;
                bool  perPixel            = i < 2;    //first two lights are per-pixel

                //interface to the light about to be created
                IMaterialPointLight light = null;

                //create the point light
                light = lights.AddPointLight(perPixel, lightPositions[i], lightHalfFalloffDistance, lightColor, lightSpecularColour);

                //adjust the lighting attenuation model, the constant defaults to 1, which prevents the light being brighter than 1.0 in the falloff equation
                //set to 0.25, the light will get really bright in close (up to 4)
                //(see light.QuadraticAttenuation remarks for an explanation of the falloff model)
                light.ConstantAttenuation = 0.25f;

                //create the light geometry (a sphere)
                if (lightGeometry == null)
                {
                    lightGeometry = new Xen.Ex.Geometry.Sphere(Vector3.One, 8, true, false, false);
                }

                //visually show the light with a light drawer
                IDraw lightSourceDrawer = new LightSourceDrawer(lightPositions[i], lightGeometry, lightColor);

                //add the light geometry to the screen
                drawToScreen.Add(lightSourceDrawer);
            }

            //create the ground disk
            GroundDisk ground = new GroundDisk(this.Content, lights, diskRadius);

            //then add it to the screen
            drawToScreen.Add(ground);
        }
Пример #10
0
        /// <summary>
        /// Draw the model. This class automatically assigns shaders when drawing
        /// </summary>
        /// <param name="state"></param>
        public void Draw(DrawState state)
        {
            if (modelData == null)
            {
                throw new InvalidOperationException("ModelData is null");
            }

            if (controller != null)
            {
                controller.WaitForAsyncAnimation(state, state.FrameIndex, true);

                if (controller.IsDisposed)
                {
                    controller = null;
                }
            }

            if (controller != null && hierarchy == null)
            {
                hierarchy = new MaterialAnimationTransformHierarchy(modelData.skeleton);
            }

            if (hierarchy != null)
            {
                hierarchy.UpdateTransformHierarchy(controller.transformedBones);
            }

            ModelInstanceShaderProvider shaderProvider = this.shaderProvider;
            MaterialLightCollection     lights         = this.lights;

            ShaderProviderFlag providerFlag;

            MaterialLightCollection.LightCollectionFlag lightsFlag;

            state.GetDrawFlag(out providerFlag);
            if (providerFlag.OverrideShaderProvider)
            {
                shaderProvider = providerFlag.ShaderProvider;
            }

            state.GetDrawFlag(out lightsFlag);
            if (lightsFlag.OverrideLightCollection)
            {
                lights = lightsFlag.LightCollection;
            }

            if (shaderProvider != null)
            {
                if (controller != null)
                {
                    shaderProvider.BeginDraw(state, controller.transformedBones, hierarchy.GetMatrixData());
                }
                else
                {
                    shaderProvider.BeginDraw(state);
                }
            }

            Vector3 boundsMin, boundsMax;

            ContainmentType cullModel = ContainmentType.Contains;

            //if there is just one geometry object, then the ICullable.CullTest() call will have been suficient.
            bool skipCullTest = this.modelData != null && this.modelData.meshes.Length == 1 && this.modelData.meshes[0].geometry.Length == 1;

            if (!skipCullTest)
            {
                if (controller != null)
                {
                    cullModel = state.Culler.IntersectBox(ref controller.boundsMin, ref controller.boundsMax);
                }
                else
                {
                    cullModel = state.Culler.IntersectBox(ref modelData.staticBounds.minimum, ref modelData.staticBounds.maximum);
                }
            }

            if (cullModel != ContainmentType.Disjoint)
            {
                for (int m = 0; m < modelData.meshes.Length; m++)
                {
                    MeshData mesh = modelData.meshes[m];

                    if (shaderProvider != null)
                    {
                        shaderProvider.BeginMesh(state, mesh);
                    }

                    ContainmentType cullMesh = cullModel;

                    if (cullModel == ContainmentType.Intersects && modelData.meshes.Length > 1)
                    {
                        if (controller != null)
                        {
                            controller.ComputeMeshBounds(m, out boundsMin, out boundsMax);
                            cullMesh = state.Culler.IntersectBox(ref boundsMin, ref boundsMax);
                        }
                        else
                        {
                            cullMesh = state.Culler.IntersectBox(ref mesh.staticBounds.minimum, ref mesh.staticBounds.maximum);
                        }
                    }

                    if (cullMesh != ContainmentType.Disjoint)
                    {
                        for (int g = 0; g < mesh.geometry.Length; g++)
                        {
                            GeometryData   geom   = mesh.geometry[g];
                            MaterialShader shader = geom.MaterialShader;

                            if (shaderProvider != null && shaderProvider.BeginGeometryShaderOverride(state, geom, lights))
                            {
                                shader = null;
                            }

                            bool cullTest = true;

                            if (cullMesh == ContainmentType.Intersects && mesh.geometry.Length > 1)
                            {
                                if (controller != null)
                                {
                                    controller.ComputeGeometryBounds(m, g, out boundsMin, out boundsMax);
                                    cullTest = state.Culler.TestBox(ref boundsMin, ref boundsMax);
                                }
                                else
                                {
                                    cullTest = state.Culler.TestBox(ref geom.staticBounds.minimum, ref geom.staticBounds.maximum);
                                }
                            }

                            if (cullTest)
                            {
                                if (shader != null)
                                {
                                    shader.AnimationTransforms = hierarchy;
                                    shader.Lights = lights;
                                    shader.Bind(state);
                                }

                                geom.Vertices.Draw(state, geom.Indices, PrimitiveType.TriangleList);
                            }

                            if (shaderProvider != null)
                            {
                                shaderProvider.EndGeometry(state, geom);
                            }
                        }
                    }

                    if (shaderProvider != null)
                    {
                        shaderProvider.EndMesh(state, mesh);
                    }
                }
            }

            if (shaderProvider != null)
            {
                shaderProvider.EndDraw(state);
            }
        }
Пример #11
0
 /// <summary>
 /// <para>Called before drawing geometry</para>
 /// <para>Return true if the shader has been overridden</para>
 /// </summary>
 /// <param name="geometry"></param>
 /// <param name="lights"></param>
 /// <returns></returns>
 /// <remarks>If pushing the world matrix, make sure to pop it in <see cref="EndGeometry"/></remarks>
 /// <param name="state"></param>
 public virtual bool BeginGeometryShaderOverride(DrawState state, GeometryData geometry, MaterialLightCollection lights)
 {
     return(false);
 }
		protected override void Initialise()
		{
			//setup ambient lighting
			this.ambientLight = new MaterialLightCollection();
			ambientLight.LightingEnabled = true;
			ambientLight.AmbientLightColour = new Vector3(0.4f, 0.2f, 0.1f);
			ambientLight.CreateDirectionalLight(new Vector3(-1, -1, 0), new Vector3(3,2,1)); // add some backlighting
			ambientLight.SphericalHarmonic.AddLight(new Vector3(2, 0.5f, 0.25f), new Vector3(0, 0, 1), 0.2f);

			//the camera for the shadows point of view, represents the direction of the light.
			Camera3D shadowCamera = new Camera3D();
			shadowCamera.LookAt(new Vector3(1, 1, 3), new Vector3(-15, 20, 20), new Vector3(0, 0, 1));

			//set the clip plane distances
			shadowCamera.Projection.FarClip = 40;
			shadowCamera.Projection.NearClip = 20;
			shadowCamera.Projection.FieldOfView *= 0.25f;


			//8bit is actually enough accuracy for this sample (given the limited range of the shadow)
			var textureFormat = SurfaceFormat.Color;
			const int resolution = 256;

			//create the shadow map texture:
			drawShadowDepth = new DrawTargetTexture2D(shadowCamera, resolution, resolution, textureFormat, DepthFormat.Depth24);
			drawShadowDepth.ClearBuffer.ClearColour = Color.White;

			//for the shadow technique used, the shadow buffer is blurred.
			//this requires an intermediate render target on the PC
			DrawTargetTexture2D blurIntermediate = null;

			//technically not required on the xbox if the render target is small enough to fit in EDRAM in one tile, but xna insists
			blurIntermediate = new DrawTargetTexture2D(shadowCamera, resolution, resolution, textureFormat, DepthFormat.None);

			//create a blur filter
			shadowDepthBlurFilter = new Xen.Ex.Filters.BlurFilter(Xen.Ex.Filters.BlurFilterFormat.SevenSampleBlur,1.0f, drawShadowDepth, blurIntermediate);

			//create the scene camera
			var camera = new Camera3D();
			camera.LookAt(new Vector3(0, 0, 3), new Vector3(10, 10, 6), new Vector3(0, 0, 1));
			camera.Projection.FieldOfView *= 0.55f;

			//create the draw target.
			drawToScreen = new DrawTargetScreen(camera);
			drawToScreen.ClearBuffer.ClearColour = Color.Black;

			//the 'scene'
			//A DrawList from Tutorial 23 is used here, this stores the 'scene', 
			//which is just a set of actors and the ground
			Tutorials.Tutorial_23.DrawList scene = new Tutorials.Tutorial_23.DrawList();

			for (int x = 0; x < 2; x++)
			for (int y = 0; y < 2; y++)
			{
				//create the actor instances
				if (x != 0 || y != 0)
					scene.Add(new Actor(this.Content, new Vector3(x*6-3, y*6-3, 0), (x + y*2 + 1) * 0.2f, 4-x*2-y));
			}

			//add the ground
			var ground = new GroundDisk(this.Content, 10, ambientLight);
			scene.Add(ground);


			//setup the draw targets...


			//create the shader provider
			var shadowOutputShaderProvider = new ShadowOutputShaderProvider();

			//add a ShadowMapDrawer to the shadow map texture
			drawShadowDepth.Add(new ShadowMapDrawer(scene, shadowOutputShaderProvider));

			//setup the scene to be drawn to the screen
			//draw the scene normally (no shadow, just ambient)
			drawToScreen.Add(scene);

			Vector3 lightColour = new Vector3(2, 1.5f, 1);

			//then draw the scene with a shadow (blended on top)
			drawToScreen.Add(new ShadowedSceneDrawer(scene, shadowOutputShaderProvider, drawShadowDepth, lightColour));

			//add a nice faded background
			Tutorial_20.BackgroundGradient background = new Tutorial_20.BackgroundGradient(new Color(1, 0.5f, 0.3f), new Color(0.2f, 0.1f, 0.2f));
			background.DrawAtMaxZDepth = true;
			drawToScreen.Add(background);


			//create a textured element that will display the shadow map texture
			var shadowDepthDisplay = new TexturedElement(drawShadowDepth, new Vector2(256, 256));
			shadowDepthDisplay.VerticalAlignment = VerticalAlignment.Top;
			this.drawToScreen.Add(shadowDepthDisplay);
		}
		public GroundDisk(ContentRegister content, float radius, MaterialLightCollection lights)
		{
			//build the disk
			var vertexData = new VertexPositionNormalTexture[256];
			var indices = new List<int>();

			for (int i = 1; i < vertexData.Length; i++)
			{
				//a bunch of vertices, in a circle!
				float angle = (float)(i-1) / (float)(vertexData.Length-2) * MathHelper.TwoPi;
				Vector3 position = new Vector3((float)Math.Sin(angle), (float)Math.Cos(angle), 0);

				vertexData[i] = new VertexPositionNormalTexture(position * radius, new Vector3(0, 0, 1), new Vector2(position.X, position.Y));
				if (i > 1)
				{
					indices.Add(0);
					indices.Add(i - 1);
					indices.Add(i);
				}
			}
			vertexData[0] = new VertexPositionNormalTexture(new Vector3(), new Vector3(0, 0, 1), new Vector2());

			this.vertices = new Vertices<VertexPositionNormalTexture>(vertexData);
			this.indices = new Indices<int>(indices);

			//create the material, and add to content
			this.material = new MaterialShader();
			this.material.LightCollection = lights;
			this.material.Textures = new MaterialTextures();

			content.Add(this);
		}
		//no change to the shader:
		public IShader BeginModel(DrawState state, MaterialLightCollection lights)
		{
			return null;
		}
		/// <summary>
		/// Draw all the model batch instances
		/// </summary>
		/// <param name="state"></param>
		public void Draw(DrawState state)
		{
			if (modelData == null)
				throw new InvalidOperationException("ModelData is null");

			if (buffers == null)
				SetupBuffers();

			int bufferIndex = 0;

			IModelShaderProvider shaderProvider = this.shaderProvider;
			MaterialLightCollection lights = this.lights;

			ModelShaderProviderFlag providerFlag;
			MaterialLightCollectionFlag lightsFlag;

			Xen.Graphics.Stack.DrawFlagStack flags = state.DrawFlags;

			flags.GetFlag(out providerFlag);
			if (providerFlag.OverrideShaderProvider)
				shaderProvider = providerFlag.ShaderProvider;

			flags.GetFlag(out lightsFlag);
			if (lightsFlag.OverrideLightCollection)
				lights = lightsFlag.LightCollection;

			IShader shader = null;
			if (shaderProvider != null)
			{
				shader = shaderProvider.BeginModel(state, lights);
				if (shader != null)
					state.Shader.Push(shader);
			}

			//loop through the model data
			for (int m = 0; m < modelData.meshes.Length; m++)
			{
				MeshData mesh = modelData.meshes[m];

				for (int g = 0; g < mesh.geometry.Length; g++)
				{
					GeometryData geom = mesh.geometry[g];
					InstanceBuffer buffer = this.buffers[bufferIndex];

					if (buffer != null)
					{
						IShader geomShader = null;
						if (shaderProvider != null)
						{
							geomShader = shaderProvider.BeginGeometry(state, geom);
							if (geomShader != null)
								state.Shader.Push(geomShader);
						}

						//draw the geometry
						geom.Vertices.DrawInstances(state, geom.Indices, PrimitiveType.TriangleList, buffer);

						if (geomShader != null)
							state.Shader.Pop();
					}

					this.buffers[bufferIndex] = null;
					bufferIndex++;
				}
			}

			if (shaderProvider != null)
			{
				shaderProvider.EndModel(state);
				if (shader != null)
					state.Shader.Pop();
			}

			drawCount = 0;
		}
		protected override void Initialise()
		{
			camera = new Camera3D();
			camera.Projection.FarClip = 300;
			camera.Projection.NearClip = 10;
			camera.Projection.FieldOfView *= 0.55f;
			//create the draw target.
			drawToScreen = new DrawTargetScreen(camera);

			//no need to clear the colour buffer, as a special background will be drawn
			drawToScreen.ClearBuffer.ClearColourEnabled = false;

			//create the light collection first
			lights = new MaterialLightCollection();

			// In this example, the rendering order has been manually optimized to reduce the number of pixels drawn
			// 
			// In xen, rendering is usually explicit. This means, when a call to Draw() is made, the draw order is
			// respected, and internally the object will be drawn using the graphics API.
			// Objects added to the screen will have Draw() called in the order they were added.
			//
			// However, the draw order can also cause performance problems.
			// In general, it's best to draw front to back, this means draw the objects closest to the screen first.
			//
			// This way, the objects at the back will be drawing behind the objects already drawn.
			// Modern video cards can quickly discard pixels if they are 'behind' what is already drawn.
			// Without front-to-back, the objects at the front could be drawing *over* objects already drawn.
			//
			// This is known as overdraw, a case where an object is drawn, only to be 'overdrawn' later in the frame.
			// Reducing overdraw can help performance, especially when complex shaders are used.
			//
			// In this example, the sample is usually vertex-limited (that is, the bottleneck is vertex processing)
			// However, it can demonstrate how optimizing for overdraw can significantly reduce the number of pixels
			// that are shaded.
			//
			// In debug builds, the DrawStatisticsDisplay class will show the number of pixels drawn in the frame.
			// 
			// With overdraw optimized draw order, ~1,000,000 pixels are drawn per frame. Without, upto 2,100,000
			// pixels are drawn per frame (usually ~1,800,000). (A 1280x720 display has 921,600 pixels)
			// 
			// This means that without an overdraw optimized draw order, on average, each pixel is being drawn
			// twice. With an optimized draw order, this number is closer to 1.1, which is very close to the 
			// optimal value of 1.0 (where each pixel is only drawn once).
			//
			// Note that the number of pixels reported by the DrawStatisticsDisplay is for the entire frame, including
			// every render target. Some PCs may not support this value, and display -1.
			//
			// One last point....
			// This sample is an extreme test of a GPU's ability to push triangles onto the screen (vertex/triangle rate).
			// However, observation will show the number of triangles drawn is often over 3,300,000!
			// Assuming half the triangles are back-face culled (an accurate approximation), this still means
			// there are around 1,650,000 triangles that are visible at any time.
			// (But remember, the vertex shader still runs for back facing triangles!)
			//
			// Assuming approximatly half of these triangles are depth occluded (very approximate), still
			// results in a huge number of visible triangles.
			// This all means that the average triangle is drawing a *very* small number of pixels, in this case,
			// the average for the actors is probably *less than 1 pixel per triangle!*.
			//
			// Triangles averaging less than 1 pixel are known as subpixel triangles.
			// For a number of reasons, subpixel triangles are very inefficent.
			// For example, if a single pixel is drawn, due to the way a video card works, the pixel shader will always
			// run in multiples of 4 pixels, so a single pixel triangle will still run the pixel shader 4 times.
			//
			// As an approximate rule:
			// Typically drawing a 1 pixel triangle will be as no faster than drawing a 16 pixel triangle.
			//
			// This makes this sample a perfect candidate for level of detail optimization, where a lower resolution
			// model is used as an actor gets further away from the screen. (Eg, two modelInstances, sharing a controller)
			//
			// The vertex shader is also very expensive, and for each triangle, it will be run upto 3 times.
			// This means the vertex shader is running more often than the pixel shader!
			// This hypothesis can be confirmed; setting the lights to per-vertex, instead of per-pixel, results
			// in a significantly *lower* frame rate!
			//
			//
			//

			bool optimizeForOverdraw = true;

			//create a list of actors to added to the screen
			var actors = new List<Actor>(500);

			//create 500 actors!
			for (int i = 0; i < 500; i++)
			{
				Actor actor = new Actor(this.Content, this.UpdateManager, lights, diskRadius);
				actors.Add(actor);
			}


			//create the lights, similar to Tutorial 14
			lights.AmbientLightColour = new Vector3(0.35f, 0.35f, 0.45f);

			Vector3[] lightPositions =
			{ 
				new Vector3(0, 30, 12), 
				new Vector3(0, -30, 12) 
			};

			//setup the two lights in the scene
			IDraw lightGeometry = null;
			IDraw lightPoleGeometry = null;
			//create geometry to display the lights
			var lightSourceGeometry = new List<IDraw>();

			//setup the lights, and create the light globe geometry
			for (int i = 0; i < lightPositions.Length; i++)
			{
				var colour = new Vector3(2, 2, 2);

				var light = lights.CreatePointLight(lightPositions[i], 1, colour, colour);

				light.SourceRadius = 6;

				if (lightGeometry == null)
				{
					lightGeometry = new Xen.Ex.Geometry.Sphere(Vector3.One, 8, true, false, false);
					lightPoleGeometry = new Xen.Ex.Geometry.Cube(new Vector3(0.4f, 0.4f, lightPositions[i].Z * 0.5f));
				}

				//visually show the light
				//create the light sphere geometry from tutorial 14.
				var position = lightPositions[i];
				lightSourceGeometry.Add(new Tutorial_14.LightSourceDrawer(position, lightGeometry, Color.LightYellow));
				position.Z *= 0.5f;
				lightSourceGeometry.Add(new Tutorial_14.LightSourceDrawer(position, lightPoleGeometry, new Color(40,40,70)));
			}

			//create the ground plane, also from tutorial 14
			var ground = new Tutorial_14.GroundDisk(this.Content, lights, diskRadius);


			//this is a special background element,
			//it draws a gradient over the entire screen, fading from dark at the bottom to light at the top.
			Color darkBlue = new Color(40, 40, 50);
			Color lightBlue = new Color(100, 100, 110);
			var background = new BackgroundGradient(lightBlue, darkBlue);


			if (optimizeForOverdraw == false)
			{
				//add all the objects in a naive order

				//first add the background (fills the entire screen, draws to every pixel, but is very fast)
				drawToScreen.Add(background);

				//then add the ground plane (all the actors will appear on top of the ground plane, overdrawing it)
				drawToScreen.Add(ground);

				//then add the lights (which are on top of the ground, overdrawing it)
				foreach (IDraw geometry in lightSourceGeometry)
					drawToScreen.Add(geometry);

				//then finally add the actors, in the order they were created
				foreach (Actor actor in actors)
					drawToScreen.Add(actor);
			}
			else
			{
				//or, add the objects in a order optimized for overdraw

#if !XBOX360
				//first, add the actors. Because they are almost always closest to the screen
				//however, use a depth sorter so the actors are sorted into a front to back draw order,
				//this sorting is based on the centre point of the cull tests they perform.

				var sorter = new Xen.Ex.Scene.DepthDrawSorter(Xen.Ex.Scene.DepthSortMode.FrontToBack);

				//Remember, the objects placed in the sorter *must* perform a valid CullTest,
				//if the CullTest simply returns true/false, no sorting will occur.
				//(Note the Actor.CullTest method)

				//to ease the CPU load, have the sorter only sort the actors every few frames...
				sorter.SortDelayFrameCount = 5;

				foreach (Actor actor in actors)
					sorter.Add(actor); // add the actors to the sorter (not the screen)

				//the sorter itself must be added to the screen!
				drawToScreen.Add(sorter); // the sorter will then draw the actors in a sorted order
#else

				//In this case (on the Xbox), because the application is heavily vertex limited
				//and already heavily CPU stretched by the animation system, the cost of 
				//sorting the actors actually causes a larger performance hit on the CPU than 
				//the time saved on the GPU. This inballance causes a frame rate drop.
				//
				//However, the reason for this may be unexpected. 
				//The framerate drop is not caused by the overhead of sorting the actors.
				//
				//Any 3D API calls made are doubly expensive on the XBOX, so in order to 
				//maintain 20fps in this sample, the primary (rendering) thread must not 
				//block, or switch to task processing.
				//If it does so, valuable rendering time is lost.
				//
				//When using a sorter, the actors are drawn in an order that is constantly changing.
				//However, they always have Update() called in a consistent order.
				//
				//During Update() the actors animation controllers will spawn thread tasks to 
				//process their animation.
				//
				//These tasks are processed on the spare xbox hardware threads, they are
				//processed in the order they were added. 
				//Processing the animation usually completes before the rendering finishes.
				//(the rendering is not delayed waiting for the animation to finish).
				//
				//However, when sorting the actors get drawn in an unpredictable order, 
				//this means the last actor added could be the first actor to draw,
				//in such a case, the chances of it's animation processing having completed
				//is *very* low. When this happens, the rendering thread has to switch to
				//processing animations, delaying rendering.
				//
				//So, for the xbox, in this sample it's best just to draw in the update order.

				foreach (Actor actor in actors)
					drawToScreen.Add(actor);

#endif

				//add the light source geometry, as they are usually below the actors, but above the ground
				foreach (IDraw geometry in lightSourceGeometry)
					drawToScreen.Add(geometry);

				//then add the ground plane, which is usually below the actors and lights.
				drawToScreen.Add(ground);

				//finally, enable a special feature of ElementRect.
				//This makes the element draw at the maximum possible Z distance
				//(behind anything else that has been drawn)
				background.DrawAtMaxZDepth = true;
				
				//add it to the screen
				drawToScreen.Add(background);
			}

			//finally,
			//create the draw statistics display
			stats = new Xen.Ex.Graphics2D.Statistics.DrawStatisticsDisplay(this.UpdateManager);
			drawToScreen.Add(stats);
		}
Пример #17
0
        /// <summary>
        /// Draw all the model batch instances
        /// </summary>
        /// <param name="state"></param>
        public void Draw(DrawState state)
        {
            if (modelData == null)
            {
                throw new InvalidOperationException("ModelData is null");
            }

            if (geometry == null)
            {
                SetupGeometry();
            }

            int geometryIndex = 0;

            BatchModelShaderProvider shaderProvider = this.shaderProvider;
            MaterialLightCollection  lights         = this.lights;

            ShaderProviderFlag providerFlag;

            MaterialLightCollection.LightCollectionFlag lightsFlag;

            state.GetDrawFlag(out providerFlag);
            if (providerFlag.OverrideShaderProvider)
            {
                shaderProvider = providerFlag.ShaderProvider;
            }

            state.GetDrawFlag(out lightsFlag);
            if (lightsFlag.OverrideLightCollection)
            {
                lights = lightsFlag.LightCollection;
            }

            if (shaderProvider != null)
            {
                shaderProvider.BeginDraw(state);
            }

            //loop through the model data
            for (int m = 0; m < modelData.meshes.Length; m++)
            {
                MeshData mesh = modelData.meshes[m];

                if (shaderProvider != null)
                {
                    shaderProvider.BeginMesh(state, mesh);
                }

                for (int g = 0; g < mesh.geometry.Length; g++)
                {
                    GeometryData geom = mesh.geometry[g];
                    GeometrySet  set  = this.geometry[geometryIndex];

                    if (set.count > 0)
                    {
                        bool instancing = state.SupportsHardwareInstancing && set.count > 2;

                        if (shaderProvider == null || !shaderProvider.BeginGeometryShaderOverride(state, geom, lights, instancing))
                        {
                            MaterialShader shader = geom.MaterialShader;

                            shader.AnimationTransforms   = null;
                            shader.UseHardwareInstancing = instancing;
                            shader.Lights = lights;

                            shader.Bind(state);
                        }

                        //draw the geometry
                        if (instancing)
                        {
                            state.DrawBatch(geom.Vertices, geom.Indices, PrimitiveType.TriangleList, null, set.instances, set.count);
                        }
                        else
                        {
                            for (int i = 0; i < set.count; i++)
                            {
                                state.PushWorldMatrixMultiply(ref set.instances[i]);

                                geom.Vertices.Draw(state, geom.Indices, PrimitiveType.TriangleList);

                                state.PopWorldMatrix();
                            }
                        }

                        if (shaderProvider != null)
                        {
                            shaderProvider.EndGeometry(state, geom);
                        }
                    }


                    set.count = 0;
                    geometryIndex++;
                }

                if (shaderProvider != null)
                {
                    shaderProvider.EndMesh(state, mesh);
                }
            }

            if (shaderProvider != null)
            {
                shaderProvider.EndDraw(state);
            }

            drawCount = 0;
        }
Пример #18
0
        protected override void Initialise()
        {
            //setup ambient lighting
            this.ambientLight               = new MaterialLightCollection();
            ambientLight.LightingEnabled    = true;
            ambientLight.AmbientLightColour = new Vector3(0.25f, 0.25f, 0.25f);
            ambientLight.AddDirectionalLight(false, new Vector3(-1, -1, 0), new Vector3(2, 2, 2));           // add some backlighting

            //setup the shadow render camera
            Camera3D shadowCamera = new Camera3D();

            shadowCamera.LookAt(new Vector3(1, 1, 3), new Vector3(-15, 20, 20), new Vector3(0, 0, 1));

            //set the clip plane distances
            shadowCamera.Projection.FarClip      = 40;
            shadowCamera.Projection.NearClip     = 20;
            shadowCamera.Projection.FieldOfView *= 0.25f;


            //8bit is actually enough accuracy for this sample (given the limited range of the shadow)
            SurfaceFormat textureFormat = SurfaceFormat.Color;
            const int     resolution    = 512;

            //create the shadow map texture:
            drawShadowDepth = new DrawTargetTexture2D(shadowCamera, resolution, resolution, textureFormat, DepthFormat.Depth24);
            drawShadowDepth.ClearBuffer.ClearColour = Color.White;

            //for the shadow technique used, the shadow buffer is blurred.
            //this requires an intermediate render target on the PC
            DrawTargetTexture2D blurIntermediate = null;

#if !XBOX360
            //not required on the xbox if the render target is small enough to fit in EDRAM in one tile
            blurIntermediate = new DrawTargetTexture2D(shadowCamera, resolution, resolution, textureFormat);
#endif
            //create a blur filter
            shadowDepthBlurFilter = new Xen.Ex.Filters.BlurFilter(Xen.Ex.Filters.BlurFilterFormat.SevenSampleBlur, 1.0f, drawShadowDepth, blurIntermediate);

            //create the scene camera
            Camera3D camera = new Camera3D();
            camera.LookAt(new Vector3(0, 0, 3), new Vector3(10, 10, 6), new Vector3(0, 0, 1));
            camera.Projection.FieldOfView *= 0.55f;

            //create the draw target.
            drawToScreen = new DrawTargetScreen(this, camera);
            drawToScreen.ClearBuffer.ClearColour = Color.Black;

            //the 'scene'
            //A DrawList from Tutorial 23 is used here, this stores the 'scene',
            //which is just a set of actors and the ground
            Tutorials.Tutorial_23.DrawList scene = new Tutorials.Tutorial_23.DrawList();

            for (int x = 0; x < 2; x++)
            {
                for (int y = 0; y < 2; y++)
                {
                    //create the actor instances
                    if (x != 0 || y != 0)
                    {
                        scene.Add(new Actor(this.Content, new Vector3(x * 6 - 3, y * 6 - 3, 0), (x + y * 2 + 1) * 0.1f, 4 - x * 2 - y));
                    }
                }
            }

            //add the ground
            GroundDisk ground = new GroundDisk(this.Content, 10, ambientLight);
            scene.Add(ground);


            //setup the draw targets...


            //create the shader provider
            ShadowOutputShaderProvider shadowOutputShaderProvider = new ShadowOutputShaderProvider();

            //add a ShadowMapDrawer to the shadow map texture
            drawShadowDepth.Add(new ShadowMapDrawer(scene, shadowOutputShaderProvider));

            //setup the scene to be drawn to the screen
            //draw the scene normally (no shadow, just ambient)
            drawToScreen.Add(scene);

            //then draw the scene with a shadow (blended on top)
            drawToScreen.Add(new ShadowedSceneDrawer(scene, shadowOutputShaderProvider, drawShadowDepth));

            //add a nice faded background
            Tutorial_20.BackgroundGradient background = new Tutorial_20.BackgroundGradient(Color.WhiteSmoke, Color.Black);
            background.DrawAtMaxZDepth = true;
            drawToScreen.Add(background);


            //create a textured element that will display the shadow map texture
            TexturedElement shadowDepthDisplay = new TexturedElement(drawShadowDepth, new Vector2(256, 256));
            shadowDepthDisplay.VerticalAlignment = VerticalAlignment.Top;
            this.drawToScreen.Add(shadowDepthDisplay);
        }
		protected override void Initialise()
		{
			camera = new Camera3D();

			//create the draw target.
			drawToScreen = new DrawTargetScreen(camera);
			//clear to dark blue
			drawToScreen.ClearBuffer.ClearColour = new Color(20, 20, 40);
			
			//create the light collection
			lights = new MaterialLightCollection();

			//set a dark blue ambient colour
			lights.AmbientLightColour = new Color(40, 40, 80).ToVector3();

			//get a list of predifined colours in the 'Color' structure using reflection
			//avoid doing this sort of thing at runtime!
			PropertyInfo[] colours = typeof(Color).GetProperties(BindingFlags.Static | BindingFlags.Public); // get all the static properties
			Random random = new Random();
			
			int lightCount = 12;

			//geometry for a light (shared for each light)
			IDraw lightGeometry = null;

			for (int i = 0; i < lightCount; i++)
			{
				//start with white.
				Color colour = Color.White;

				//try and pick a random colour from the list, using reflection to get the value of the property
				try
				{
					//pick a random field info object (a reflected colour property)
					var randomColourField = colours[random.Next(colours.Length)];

					//try and get it's value
					object colourObject = randomColourField.GetValue(null, null);

					if (colourObject is Color)
						colour = (Color)colourObject;
				}
				catch
				{
					//this shouldn't fail, but always be careful with reflection...
					//typically this would be handled correctly, but here, just stick with white.
				}


				float angle = (float)i / (float)lightCount * (float)Math.PI * 2;
				Vector3 position = new Vector3((float)Math.Sin(angle) * (diskRadius + 1), (float)Math.Cos(angle) * (diskRadius + 1), 4);

				float intensity = 1;

				//interface to the light about to be created
				IMaterialPointLight light = null;

				//create the point light
				light = lights.CreatePointLight(position, intensity, colour, colour);
				
				light.SourceRadius = 5;

				//create the light geometry (a sphere)
				if (lightGeometry == null)
					lightGeometry = new Xen.Ex.Geometry.Sphere(Vector3.One, 8, true, false, false);

				//visually show the light with a light drawer
				IDraw lightSourceDrawer = new LightSourceDrawer(position, lightGeometry, colour);

				//add the light geometry to the screen
				drawToScreen.Add(lightSourceDrawer);
			}

			//add the actor
			actor = new Tutorials.Tutorial_11.Actor(this.Content, this.lights);

			drawToScreen.Add(actor);


			//create the ground disk
			GroundDisk ground = new GroundDisk(this.Content, lights, diskRadius);

			//then add it to the screen
			drawToScreen.Add(ground);
		}
Пример #20
0
        protected override void Initialise()
        {
            Resource.EnableResourceTracking();

            camera = new Camera3D();
            camera.Projection.FarClip      = 300;
            camera.Projection.NearClip     = 10;
            camera.Projection.FieldOfView *= 0.55f;
            //create the draw target.
            drawToScreen = new DrawTargetScreen(this, camera);

            //no need to clear the colour buffer, as a special background will be drawn
            drawToScreen.ClearBuffer.ClearColourEnabled = false;

            //create the light collection first
            lights = new MaterialLightCollection();

            // In this example, the rendering order has been manually optimized to reduce the number of pixels drawn
            //
            // In xen, rendering is usually explicit. This means, when a call to Draw() is made, the draw order is
            // respected, and internally the object will be drawn using the graphics API.
            // Objects added to the screen will have Draw() called in the order they were added.
            //
            // However, the draw order can also cause performance problems.
            // In general, it's best to draw front to back, this means draw the objects closest to the screen first.
            //
            // This way, the objects at the back will be drawing behind the objects already drawn.
            // Modern video cards can quickly discard pixels if they are 'behind' what is already drawn.
            // Without front-to-back, the objects at the front could be drawing *over* objects already drawn.
            //
            // This is known as overdraw, a case where an object is drawn, only to be 'overdrawn' later in the frame.
            // Reducing overdraw can help performance, especially when complex shaders are used.
            //
            // In this example, the sample is usually vertex-limited (that is, the bottleneck is vertex processing)
            // However, it can demonstrate how optimizing for overdraw can significantly reduce the number of pixels
            // that are shaded.
            //
            // In debug builds, the DrawStatisticsDisplay class will show the number of pixels drawn in the frame.
            //
            // With overdraw optimized draw order, ~1,000,000 pixels are drawn per frame. Without, upto 2,100,000
            // pixels are drawn per frame (usually ~1,800,000). (A 1280x720 display has 921,600 pixels)
            //
            // This means that without an overdraw optimized draw order, on average, each pixel is being drawn
            // twice. With an optimized draw order, this number is closer to 1.1, which is very close to the
            // optimal value of 1.0 (where each pixel is only drawn once).
            //
            // Note that the number of pixels reported by the DrawStatisticsDisplay is for the entire frame, including
            // every render target. Some PCs may not support this value, and display -1.
            //
            // One last point....
            // This sample is an extreme test of a GPU's ability to push triangles onto the screen (vertex/triangle rate).
            // However, observation will show the number of triangles drawn is often over 3,300,000!
            // Assuming half the triangles are back-face culled (an accurate approximation), this still means
            // there are around 1,650,000 triangles that are visible at any time.
            // (But remember, the vertex shader still runs for back facing triangles!)
            //
            // Assuming approximatly half of these triangles are depth occluded (very approximate), still
            // results in a huge number of visible triangles.
            // This all means that the average triangle is drawing a *very* small number of pixels, in this case,
            // the average for the actors is probably *less than 1 pixel per triangle!*.
            //
            // Triangles averaging less than 1 pixel are known as subpixel triangles.
            // For a number of reasons, subpixel triangles are very inefficent.
            // For example, if a single pixel is drawn, due to the way a video card works, the pixel shader will always
            // run in multiples of 4 pixels, so a single pixel triangle will still run the pixel shader 4 times.
            //
            // This makes this sample a perfect candidate for level of detail optimization, where a lower resolution
            // model is used as an actor gets further away from the screen.
            //
            // The vertex shader is also very expensive, and for each triangle, it will be run upto 3 times.
            // This means the vertex shader is quite possibly running more often than the pixel shader.
            // This hypothesis can be confirmed; setting the lights to per-vertex, instead of per-pixel, results
            // in a significantly *lower* frame rate!
            //
            //
            //

            bool optimizeForOverdraw = true;

            //create a list of actors to added to the screen
            List <Actor> actors = new List <Actor>(500);

            //create 500 actors!
            for (int i = 0; i < 500; i++)
            {
                Actor actor = new Actor(this.Content, this.UpdateManager, lights, diskRadius);
                actors.Add(actor);
            }


            //create the lights, similar to Tutorial 14
            lights.AmbientLightColour = new Vector3(0.45f, 0.45f, 0.5f);

            Vector3[] lightPositions = new Vector3[]
            {
                new Vector3(0, 30, 12),
                new Vector3(0, -30, 12)
            };

            //setup the two lights in the scene
            IDraw lightGeometry     = null;
            IDraw lightPoleGeometry = null;
            //create geometry to display the lights
            List <IDraw> lightSourceGeometry = new List <IDraw>();

            //setup the lights, and create the light globe geometry
            for (int i = 0; i < lightPositions.Length; i++)
            {
                Vector3 colour = new Vector3(5, 5, 5);

                IMaterialPointLight light = lights.AddPointLight(i < 2, lightPositions[i], 8, colour, colour);

                light.ConstantAttenuation  = 0.25f;                // make the ligh falloff curve a lot sharper (brighter at the centre)
                light.LinearAttenuation    = 0;
                light.QuadraticAttenuation = 0.075f;               //approximate inverse distance in which the brightness of the light will halve

                if (lightGeometry == null)
                {
                    lightGeometry     = new Xen.Ex.Geometry.Sphere(Vector3.One, 8, true, false, false);
                    lightPoleGeometry = new Xen.Ex.Geometry.Cube(new Vector3(0.4f, 0.4f, lightPositions[i].Z * 0.5f));
                }

                //visually show the light
                //create the light sphere geometry from tutorial 14.
                Vector3 position = lightPositions[i];
                lightSourceGeometry.Add(new Tutorial_14.LightSourceDrawer(position, lightGeometry, Color.LightYellow));
                position.Z *= 0.5f;
                lightSourceGeometry.Add(new Tutorial_14.LightSourceDrawer(position, lightPoleGeometry, new Color(40, 40, 70)));
            }

            //create the ground plane, also from tutorial 14
            Tutorial_14.GroundDisk ground = new Tutorial_14.GroundDisk(this.Content, lights, diskRadius);


            //this is a special background element,
            //it draws a gradient over the entire screen, fading from dark at the bottom to light at the top.
            Color darkBlue  = new Color(40, 40, 50);
            Color lightBlue = new Color(100, 100, 110);
            BackgroundGradient background = new BackgroundGradient(lightBlue, darkBlue);


            if (optimizeForOverdraw == false)
            {
                //add all the objects in a naive order

                //first add the background (fills the entire screen, draws to every pixel, but is very fast)
                drawToScreen.Add(background);

                //then add the ground plane (all the actors will appear on top of the ground plane, overdrawing it)
                drawToScreen.Add(ground);

                //then add the lights (which are on top of the ground, overdrawing it)
                foreach (IDraw geometry in lightSourceGeometry)
                {
                    drawToScreen.Add(geometry);
                }

                //then finally add the actors, in the order they were created
                foreach (Actor actor in actors)
                {
                    drawToScreen.Add(actor);
                }
            }
            else
            {
                //or, add the objects in a order optimized for overdraw

#if !XBOX360
                //first, add the actors. Because they are almost always closest to the screen
                //however, use a depth sorter so the actors are sorted into a front to back draw order,
                //this sorting is based on the centre point of the cull tests they perform.

                Xen.Ex.Scene.DepthDrawSorter sorter = new Xen.Ex.Scene.DepthDrawSorter(Xen.Ex.Scene.DepthSortMode.FrontToBack);

                //Remember, the objects placed in the sorter *must* perform a valid CullTest,
                //if the CullTest simply returns true/false, no sorting will occur.
                //(Note the Actor.CullTest method)

                //to ease the CPU load, have the sorter only sort the actors every few frames...
                sorter.SortDelayFrameCount = 5;

                foreach (Actor actor in actors)
                {
                    sorter.Add(actor);                     // add the actors to the sorter (not the screen)
                }
                //the sorter itself must be added to the screen!
                drawToScreen.Add(sorter);                 // the sorter will then draw the actors in a sorted order
#else
                //In this case (on the Xbox), because the application is heavily vertex limited
                //and already heavily CPU stretched by the animation system, the cost of
                //sorting the actors actually causes a larger performance hit on the CPU than
                //the time saved on the GPU. This inballance causes a frame rate drop.
                //
                //However, the reason for this may be unexpected.
                //The framerate drop is not caused by the overhead of sorting the actors.
                //
                //Any 3D API calls made are doubly expensive on the XBOX, so in order to
                //maintain 20fps in this sample, the primary (rendering) thread must not
                //block, or switch to task processing.
                //If it does so, valuable rendering time is lost.
                //
                //When using a sorter, the actors are drawn in an order that is constantly changing.
                //However, they always have Update() called in a consistent order.
                //
                //During Update() the actors animation controllers will spawn thread tasks to
                //process their animation.
                //
                //These tasks are processed on the three spare xbox hardware threads, they are
                //processed in the order they were added.
                //Processing the animation usually completes before the rendering finishes.
                //(the rendering is not delayed waiting for the animation to finish).
                //
                //However, when sorting the actors get drawn in an unpredictable order,
                //this means the last actor added could be the first actor to draw,
                //in such a case, the chances of it's animation processing having completed
                //is *very* low. When this happens, the rendering thread has to switch to
                //processing animations, delaying rendering.
                //
                //So, for the xbox, it's best just to draw in the update order.

                foreach (Actor actor in actors)
                {
                    drawToScreen.Add(actor);
                }
#endif

                //add the light source geometry, as they are usually below the actors, but above the ground
                foreach (IDraw geometry in lightSourceGeometry)
                {
                    drawToScreen.Add(geometry);
                }

                //then add the ground plane, which is usually below the actors and lights.
                drawToScreen.Add(ground);

                //finally, enable a special feature of ElementRect.
                //This makes the element draw at the maximum possible Z distance
                //(behind anything else that has been drawn)
                background.DrawAtMaxZDepth = true;

                //add it to the screen
                drawToScreen.Add(background);
            }

            //finally,
            //create the draw statistics display
            stats = new Xen.Ex.Graphics2D.Statistics.DrawStatisticsDisplay(this.UpdateManager);
            drawToScreen.Add(stats);
        }
		public GeometryDrawer(Vector3 position)
		{
			//create the quad
			geometry = new DynamicQuadGeometry();

			//setup the world matrix
			worldMatrix = Matrix.CreateTranslation(position);

			//create a basic lighting shader with some average looking lighting :-)
			MaterialShader material = new MaterialShader();
			material.SpecularColour = Color.LightYellow.ToVector3() * 0.5f;

			Vector3 lightDirection = new Vector3(-1, -1, -1); //a dramatic direction

			//Note: To use vertex colours with a MaterialShader, UseVertexColour has to be set to true
			material.UseVertexColour = true;

			//create a directional light
			MaterialLightCollection lights = new MaterialLightCollection();
			lights.CreateDirectionalLight(-lightDirection, Color.WhiteSmoke);

			material.LightCollection = lights;

			this.shader = material;
		}
		protected override void Initialise()
		{
			camera = new Camera3D();

			//create the draw target.
			drawToScreen = new DrawTargetScreen(camera);
			//clear to dark blue
			drawToScreen.ClearBuffer.ClearColour = new Color(20, 20, 40);

			//create the light collection
			lights = new MaterialLightCollection();
			//set a dark blue ambient colour
			lights.AmbientLightColour = new Color(40, 40, 80).ToVector3();

			//positions for two lights
			Vector3[] lightPositions = new Vector3[] 
			{ 
				new Vector3(0, 30, 4), 
				new Vector3(0, -30, 4) 
			};

			//geometry for a light (shared for each light)
			IDraw lightGeometry = null;

			for (int i = 0; i < lightPositions.Length; i++)
			{
				float intensity = 2;
				Color lightColor = Color.LightYellow;
				Color lightSpecularColour = Color.WhiteSmoke;

				//interface to the light about to be created
				IMaterialPointLight light = null;

				//create the point light
				light = lights.CreatePointLight(lightPositions[i], intensity, lightColor, lightSpecularColour);
				
				//Adjusting this value controls how quickly the light falloff occurs.
				//A larger value will produce a slower falloff, and result in a softer, brighter light.
				//A smaller value will produce a darker, but sharper light source.
				//Generally, if you reduce this value, increase the intensity to compensate.
				light.SourceRadius = 4;

				//create the light geometry (a sphere)
				if (lightGeometry == null)
					lightGeometry = new Xen.Ex.Geometry.Sphere(Vector3.One, 8, true, false, false);

				//visually show the light with a light drawer
				var lightSourceDrawer = new LightSourceDrawer(lightPositions[i], lightGeometry,lightColor);

				//add the light geometry to the screen
				drawToScreen.Add(lightSourceDrawer);
			}

			//create the ground disk
			var ground = new GroundDisk(this.Content, lights, diskRadius);

			//then add it to the screen
			drawToScreen.Add(ground);
		}
		public GeometryDrawer(Vector3 position)
		{
			//NEW CODE
			//create the quad
			this.geometry = new QuadGeometry();

			//setup the world matrix
			this.worldMatrix = Matrix.CreateTranslation(position);

			//create a lighting shader with some average looking lighting :-)
			var material = new MaterialShader();
			material.SpecularColour = Color.LightYellow.ToVector3();//with a nice sheen

			var lightDirection = new Vector3(0.5f,1,-0.5f); //a less dramatic direction

			var lights = new MaterialLightCollection();
			lights.AmbientLightColour = Color.DarkGoldenrod.ToVector3() * 0.5f;
			lights.CreateDirectionalLight(-lightDirection, Color.WhiteSmoke);

			material.LightCollection = lights;

			this.shader = material;
		}
		protected override void Initialise()
		{
			Camera3D camera = new Camera3D();
			camera.LookAt(Vector3.Zero, new Vector3(0, 0, 5), Vector3.UnitY);

			//create the draw target.
			drawToScreen = new DrawTargetScreen(camera);
			drawToScreen.ClearBuffer.ClearColour = Color.CornflowerBlue;



			//create a shader to display the geometry (this is the same as tutorial 02)
			var lightDirection = new Vector3(1.0f, 0.5f, 0.5f);
			var material = new MaterialShader();
			material.SpecularColour = Color.LightYellow.ToVector3();				//give the material a nice sheen

			var lights = new MaterialLightCollection();

			lights.AmbientLightColour = Color.CornflowerBlue.ToVector3() * 0.5f;	//set the ambient
			lights.CreateDirectionalLight(lightDirection, Color.Gray);				//add the first of two light sources
			lights.CreateDirectionalLight(-lightDirection, Color.DarkSlateBlue);

			material.LightCollection = lights;

			//create a simpler shader to display the wireframe (and also used for the bounding cube)
			var simpleShader = new Xen.Ex.Shaders.FillSolidColour();
			simpleShader.FillColour = Vector4.One * 0.01f;


			var sphereSize = new Vector3(0.5f, 0.5f, 0.5f);

			//create the complex sphere, this will have ~100k triangles.
			//pass in a shader for wireframe rendering
			sphere = new GeometryDrawer(new Xen.Ex.Geometry.Sphere(sphereSize, 200), material, simpleShader);

			//create the bounding cube
			sphereBoundingBox = new GeometryDrawer(new Xen.Ex.Geometry.Cube(sphereSize), simpleShader, null);

			//create the occluding cube, and position it close to the camera
			cube = new GeometryDrawer(new Xen.Ex.Geometry.Cube(Vector3.One), material, null);
			cube.position = new Vector3(0, 0, 2.75f);


			//add the cube first (so it can draw first, potentially occluding the sphere)
			//if the cube was added second, it would have no effect, as it would draw after the sphere
			drawToScreen.Add(cube);


			//create the predicate, passing in the sphere and bounding box
			var predicate = new Xen.Ex.Scene.DrawPredicate(sphere, sphereBoundingBox);

			//add the DrawPredicate (the DrawPredicate draws it's children)
			drawToScreen.Add(predicate);


			//statistic overlay
			statOverlay = new Xen.Ex.Graphics2D.Statistics.DrawStatisticsDisplay(this.UpdateManager);
			drawToScreen.Add(statOverlay);
		}
		//constructor
		public SphereDrawer(Vector3 position)
		{
			//setup the sphere
			var size = new Vector3(1,1,1);
			//use a prebuilt sphere geometry class
			sphereGeometry = new Sphere(size, 32);

			//setup the world matrix
			worldMatrix = Matrix.CreateTranslation(position);

			//create a lighting shader with some nice looking lighting
			var material = new MaterialShader();
			material.SpecularColour = Color.LightYellow.ToVector3();//with a nice sheen

			var lightDirection = new Vector3(0.5f,1,-0.5f); //a dramatic direction

			var lights = new MaterialLightCollection();
			lights.AmbientLightColour = Color.CornflowerBlue.ToVector3() * 0.5f;
			lights.CreateDirectionalLight(lightDirection, Color.Gray);//two light sources
			lights.CreateDirectionalLight(-lightDirection, Color.DarkSlateBlue);

			material.LightCollection = lights;

			this.shader = material;
		}