gr_tut9_screenshot.jpg

StencilShadows.cs

#region Using directives

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using Microsoft.DirectX.Direct3D;

using JadEngine;
using JadEngine.Video;
using JadEngine.Core;
using JadEngine.Mathematics;
using JadEngine.Scene;
using JadEngine.Scene.MD5;
using JadEngine.Physics;
using JadEngine.Particles;
using JadEngine.Sound;
using JadEngine.Tools;
using JadEngine.Input;

#endregion

namespace Tutorial
{
	/// <summary>
	/// This example will teach you to use stencil shadows.
	/// You´ll also learn how to make a light that always looks to a scene node (targeting).
	/// </summary>
	public class StencilShadows : JApplication
	{
		#region Fields

		/// <summary>
		/// Indicates if the help must be shown in the screen or not
		/// </summary>
		bool showHelp = true;

		/// <summary>
		/// TODO
		/// </summary>
		JMeshObject sphere;

		JSprite sprite;

		#endregion

		#region Methods

		/// <summary>
		/// The engine calls this method after creating the device
		/// </summary>
		/// <param name="form">Form used as window</param>
		/// <returns>True if everything went right</returns>
		public override bool InitGame(Form form)
		{
			// Create the fonts and texture objects
			Jad.AfterCreateDevice();

			// Load default textures, scenes, shaders,...
			Jad.LoadCreateInHouse();

			// Create the scene
			CreateScene();

			// We create and sprite to show the shadowmap and shadowmask RT
			sprite = new JSprite();

			// Set the ambient light
			Jad.Scene.Lights.Ambient = new JColor(0.2f, 0.2f, 0.2f);

			// Set the camera
			Jad.Scene.Camera.Transform.Position = new Vector3(0, 0f, -2f);

			// Everything is set, start the engine
			Jad.Begin();

			// Create input class to manage the keyboard and the mouse
			Jad.CreateInput();

			return true;
		}

		/// <summary>
		/// Creates a spot light
		/// </summary>
		/// <param name="position">Position of the light</param>
		/// <param name="lightColor">Color of the light</param>
		void CreateLight(string name, Vector3 position, JColor lightColor)
		{
			JSpotLight spotLight = (JSpotLight) Jad.Scene.Lights.Create(name, JLightType.Spot);

			spotLight.Transform.Position = position;

			spotLight.Multiplier = 1f;

			spotLight.Attenuation.Type = JLightAttenuationType.DualRadius;

			spotLight.Attenuation.Start = 2f;

			spotLight.Attenuation.End = 3f;

			spotLight.Color = lightColor;

			spotLight.AffectDiffuse = true;

			spotLight.AffectSpecular = true;

			// It casts shadows
			spotLight.CastShadows = true;

			spotLight.HotSpot = 25f;

			spotLight.FallOff = 50f;

			// Target the sphere object. The light will always face
			// the sphere while moving
			spotLight.Transform.Target = sphere;
		}

		/// <summary>
		/// Creates the room of the scene
		/// </summary>
		void CreateRoom()
		{
			JMesh cubeMesh = JMesh.CreateCube(2f, 2f, 2f);

			// Invert the cube faces, as we want to be inside the room
			cubeMesh.IndexBuffer.InvertFaces();

			JMeshObject cube = Jad.Scene.MeshObjects.Create("room", false);

			cube.Mesh = cubeMesh;

			JMaterial[] material = new JMaterial[1];

			material[0] = Jad.Scene.Materials.Create();

			JMaterialLayer layer = new JMaterialLayer();

			material[0].AddLayer(layer);

			layer.DiffuseMap.Texture = Jad.Video.Textures.Create2D("brick_d", true);

			layer.DiffuseMap.UTile = layer.DiffuseMap.VTile = 4f;

			cube.Material = material;
		}

		/// <summary>
		/// Creates a sphere that casts shadows
		/// </summary>
		void CreateSphere()
		{
			float radius = 0.25f;

			JMesh sphereMesh = JMesh.CreateSphere(radius, 20, 20);

			sphere = Jad.Scene.MeshObjects.Create("sphere", false);

			sphere.Mesh = sphereMesh;

			JMaterial[] material = new JMaterial[1];

			material[0] = Jad.Scene.Materials.Create();

			JMaterialLayer layer = new JMaterialLayer();

			material[0].AddLayer(layer);

			layer.DiffuseMap.Texture = Jad.Video.Textures.Create2D("mancha", true);

			sphere.Material = material;

			sphere.Transform.Position = new Vector3(0, -1f + 0.25f, 0);

			// This object casts shadows
			sphere.CastShadows = true;

			// Set the extrusion contact of the shadowvolume
			sphere.Mesh.ShadowVolume.ExtrusionConstant = 5f;

			// Optimize the shadowvolume in a 75% of the original mesh vertices
			sphere.Mesh.ShadowVolume.Optimize(0.75f);
		}

		/// <summary>
		/// Creates the scene
		/// </summary>
		void CreateScene()
		{
			// Create the room
			CreateRoom();

			// Create the spehre
			CreateSphere();

			// Create a red spot light
			CreateLight("red", new Vector3(0.75f, 0.4f, 0f), JColor.RedColor);

			// Creamos una luz spot de color blanco
			CreateLight("White", new Vector3(0f, 0.4f, 0.4f), JColor.White);

			// Set the shadow values

			Jad.Scene.Shadows.ShadowMode = JShadowMode.StencilVolume;

			// Indicamos que queremos utilizar el modo depthpass, en lugar de depthfail
			Jad.Scene.Shadows.Stencil.DepthPass = true;

			// We are going to use the shadows cache. This system saves all the volumes
			// that are generated and if the same volume is generated again, then it uses
			// the one in the cache (much faster). 
			// But it´s pretty dangerous because if the light or the object moves, it will
			// generate volumes constantly that won´t be reusable and will eat all the
			// memory. So we only generate the cache of 1 light, the static one

			Jad.Scene.Shadows.Stencil.ShadowVolumes.AddToCache = true;

			// We need to compute the transformation nodes to compute
			// the volumes
			Jad.Scene.Root.TransformDown();

			sphere.Mesh.ShadowVolume.Build(Jad.Scene.Lights[1], sphere, false);

			// Now we should disable it, because this light will rotate around the sphere
			// and that would generate a lot of volumes. But for this example will
			// let the cache enabled
		}

		/// <summary>
		/// This method is called every frame and it´s where the input
		/// events and the game action must be placed
		/// </summary>
		/// <returns>True to continue, false to exit the application</returns>
		public override bool Update()
		{
			// Exit the app?
			if (Jad.Input.Keyboard[Key.Escape].Down) return false;

			if (Jad.Input.Keyboard[Key.F1].Pressed) showHelp = !showHelp;

			if (Jad.Input.Keyboard[Key.G].Pressed)
				Jad.Scene.ShowGizmos = !Jad.Scene.ShowGizmos;

			if (Jad.Input.Keyboard[Key.O].Pressed)
				Jad.Scene.Shadows.Stencil.Debug = !Jad.Scene.Shadows.Stencil.Debug;

			if (Jad.Input.Keyboard[Key.P].Pressed)
			{
				if (Jad.Scene.Shadows.ShadowMode == JShadowMode.StencilVolume)
					Jad.Scene.Shadows.ShadowMode = JShadowMode.None;
				else
					Jad.Scene.Shadows.ShadowMode = JShadowMode.StencilVolume;
			}

			// Move the light in a circle
			JBaseLight light = Jad.Scene.Lights[0];

			float z = (float) Math.Sin(Jad.Timer.Time) * 0.5f;
			float x = (float) Math.Cos(Jad.Timer.Time) * 0.5f;

			light.Transform.Position = new Vector3(x, 0.2f, z);

			// Everything was right, continue
			return true;
		}

		/// <summary>
		/// Render method
		/// </summary>
		public override void Render()
		{
			JView backbuffer = Jad.Video.Views[0];

			backbuffer.Render();
			/*
			// Prepare the scene to start the render
			Jad.Scene.Begin();

			// Render all the scene objects
			Jad.Scene.Render();

			// Do the post-production
			Jad.Scene.ProcessPostProduction();

			// Render various things of the scene (gizmos, axes, names,...)
			Jad.Scene.RenderMiscellaneous();
			*/
			sprite.SetPositionSize(0, 0, 100, 100);
			sprite.Effect = Jad.Video.Effects.InHouse.PosColorTex1;
			sprite.Texture = Jad.Video.Views[0].RenderTargets.ShadowMask.Texture;
			sprite.Render();
			if (showHelp)
			{
				// Get access to the 1st font. The engine creates a font by default
				JFont font = Jad.Video.Fonts[0];

				// Start fonts rendering
				Jad.Video.Fonts.Begin();

				// Write text in the first line, position x=0, yellow color
				font.RenderLine(Jad.Version + ". Press ESC to exit. Press G to Show/Hide Gizmos. F1 show/hide text", 0, JColor.Yellow);

				// Write text in the second line, position x=0, white color
				font.RenderLine(Jad.Video.Views.CurrentView.Stats.Fps + " FPS", 0, JColor.White);

				int memory = Jad.Scene.Shadows.Stencil.ShadowVolumes.TotalMemoryUsage / 1024;

				font.RenderLine("Shadow Volume matched: " + Jad.Scene.Shadows.Stencil.ShadowVolumes.Matched.ToString() + " List Count:" + Jad.Scene.Shadows.Stencil.ShadowVolumes.NumElements.ToString() + " Total memory:" + memory.ToString() + " k", 0, JColor.White);

				font.RenderLine("Press P to activate/deactivate shadows", 0, JColor.White);
				font.RenderLine("Press O to activate/deactivate debug on shadows", 0, JColor.White);

				// End fonts rendering
				Jad.Video.Fonts.End();
			}

			// End the scene
			//Jad.Scene.End();

			backbuffer.Present();
		}

		#endregion
	}
}

Last edited Mar 8, 2007 at 12:24 PM by Vicente, version 4

Comments

No comments yet.