gr_tut18_screenshot.jpg

WorldCollisions.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.Import;
using JadEngine.Input;

#endregion

namespace Tutorial
{
	/// <summary>
	/// This example will teach you to use Newton to work with a collisionable world.
	/// Also, you'll see how to apply the ghost effect to a mesh object.
	/// Finally, you'll see the way Newton can calculate the distance from a point
	/// to a convex collision volume and how to do the sliding displacement effect.
	/// </summary>
	public class WorldCollisions : JApplication
	{
		#region Fields

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

		/// <summary>
		/// TODO
		/// </summary>
		JCameraFirstPerson camera;

		/// <summary>
		/// TODO
		/// </summary>
		JMeshObject targetObject;

		/// <summary>
		/// TODO
		/// </summary>
		JMeshObject sphereContactPoint;

		/// <summary>
		/// TODO
		/// </summary>
		JCollision collision;

		/// <summary>
		/// TODO
		/// </summary>
		Vector3 contactPoint = Vector3.Empty;

		/// <summary>
		/// TODO
		/// </summary>
		Vector3 normal = Vector3.Empty;

		/// <summary>
		/// TODO
		/// </summary>
		float distance;

		#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();

			// Set the fixed mode, so the engine works at a fixed frame rate
			Jad.Timer.FixedMode = true;
			Jad.Timer.FixedModeFPS = 1.0f / 30.0f;	// 30 fps

			// Create the Newton World
			Jad.Physics.Create();

			// Load the scene
			Jad.Import.Load("particles.haddd");

			// Build a collision tree for the world
			Jad.Physics.BuildCollisionTree(Jad.Import.MeshObjects, false);

			// Create a mesh object that will be used later to show how "Minimum distance to object" works
			CreateHebe();

			// Create an sphere to show the contact point
			CreateSphere();

			// Get a reference to the camera created by the engine
			camera = (JCameraFirstPerson) Jad.Scene.Camera;

			// Set some new properties
			camera.Transform.Position = new Vector3(0, 2, 0);
			camera.Transform.Angles = new Vector3(0.0f, (float) Math.PI, 0.0f);
			camera.FarPlane = 50.0f;

			// Set the world collision to true
			camera.UseWorldColision = true;

			// Our callback function where we'll manage the camera collision detection
			camera.CheckCollisionDelegate = new JCameraFirstPerson.CheckCollision(CheckCameraCollision);

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

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

			return true;
		}

		/// <summary>
		/// Callback function where we'll manage the camera collision detection
		/// </summary>
		/// <param name="After">The last position</param>
		/// <param name="Before">The last safe position</param>
		/// <returns>Returns the new position</returns>
		Vector3 CheckCameraCollision(Vector3 After, Vector3 Before)
		{
			float t;

			// Radius of the sphere we'll use as collision primitive for the camera
			float collisionRadius = 0.7f;

			// Our final position
			Vector3 finalPosition = After;

			// Calculate the camera velocity
			Vector3 velocity = After - Before;
			// Length of the velocity vector
			float vLength = velocity.Length();
			// Normalized velocity vector
			Vector3 vDirection = Vector3.Normalize(velocity);

			// Build the segment we'll use to test collision on
			Vector3 p0 = Before;
			Vector3 p1 = Before + velocity + (vDirection * collisionRadius);

			// Check collision with the world
			if (Jad.Physics.WorldRayCast(ref p0, ref p1, out t))
			{
				// We've collided, so calculate the new position...
				finalPosition = Jad.Physics.RayCast.ContactPoint - (vDirection * collisionRadius);

				// Compute the distance travelled by the camera
				float distanceFromOrigin = t - collisionRadius;

				// Now, compute the remaining distance
				float distanceLeft = vLength - distanceFromOrigin;

				// Scale it down a bit...
				distanceLeft *= 0.8f;

				// Calculate the remaining velocity vector
				Vector3 remainingVelocity = vDirection * distanceLeft;

				// Calculate the sliding plane normal
				Vector3 slidingPlaneNormal = -Jad.Physics.RayCast.Normal;

				// Calculate the projection of the velocity vector onto the sliding plane normal
				Vector3 projectedVelocity = slidingPlaneNormal * Vector3.Dot(slidingPlaneNormal, remainingVelocity);

				// Calculate the new velocity vector
				Vector3 newVelocity = remainingVelocity - projectedVelocity;

				// Finally we calculate the final position
				finalPosition += newVelocity;
			}

			return finalPosition;
		}

		/// <summary>
		/// Creates the hebe object
		/// </summary>
		void CreateHebe()
		{
			// Load the scene
			Jad.Import.Load("hebe.haddd");

			targetObject = Jad.Import.MeshObjects[0];

			targetObject.Material[0].Priority = JMaterialPriority.PostProcess;

			JMaterialLayer layer = targetObject.Material[0].Layers[0];

			layer.Ghost = true;
			layer.GhostAdd = 0f;
			layer.GhostPower = 1f;
			layer.DiffuseMap.TextureEnabled = false;
			layer.DiffuseMap.Color = new JColor(0, 0, 1);
			layer.RenderStates.AlphaBlendEnable = true;
			layer.RenderStates.SourceBlend = Blend.One;
			layer.RenderStates.DestinationBlend = Blend.One;

			collision = new JCollision();

			Matrix matrix = Matrix.Translation(new Vector3(0, 1, 3));

			collision.CreateConvexHull(targetObject.Mesh.VertexBuffer.Position);

			// Create a Rigid body. Rigid bodies are the objects that have
			// the colision and physic properties set. We associate the collision
			// object we just created with the JMeshObject
			JRigidBody body = Jad.Physics.RigidBodies.Create(collision, targetObject);

			// Set the mass. In Newton, an object with 0 mass is considered a static object,
			// that is, you can collide with it but it won´t react to anything
			body.Mass = 0f;
			body.Matrix = matrix;

			// We do not release here the collision because we need it to compute the distance
		}

		/// <summary>
		/// Creates the sphere
		/// </summary>
		void CreateSphere()
		{
			float radius = 0.05f;

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

			// A JMeshObject is an object with the information about the meshes and the
			// materials. It´s the element we´ll use to render the meshes.

			// We create a new JMeshObject in the scene. We set that we don´t want to
			// create a new mesh object, as we have just done it.
			sphereContactPoint = Jad.Scene.MeshObjects.Create("sphere", false);

			// Now, we associate the mesh with the meshobject
			sphereContactPoint.Mesh = mesh;

			// The material
			JMaterial[] material = new JMaterial[1];
			material[0] = Jad.Scene.Materials.Create();
			JMaterialLayer layer = new JMaterialLayer();
			material[0].AddLayer(layer);
			layer.DiffuseMap.TextureEnabled = false;
			layer.DiffuseMap.Color = JColor.Yellow;
			sphereContactPoint.Material = material;
			sphereContactPoint.AffectLight = false;
			layer.EmissiveMap.Color = JColor.Yellow;
		}

		/// <summary>
		/// Releases the objects
		/// </summary>
		public override void End()
		{
			collision.Release();
		}

		/// <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 G key was pressed we activate / deactivate the gizmos
			if (Jad.Input.Keyboard[Key.G].Pressed)
				Jad.Scene.ShowGizmos = !Jad.Scene.ShowGizmos;

			// If they P key was pressed you can see / hide Newton collision objects
			if (Jad.Input.Keyboard[Key.P].Pressed)
				Jad.Physics.Debug = !Jad.Physics.Debug;

			// if C was pressed, switch on/off the world collision
			if (Jad.Input.Keyboard[Key.C].Pressed)
				camera.UseWorldColision = !camera.UseWorldColision;

			ComputeDistance();

			// Everything was right, continue
			return true;
		}

		/// <summary>
		/// Computes the distance
		/// </summary>
		void ComputeDistance()
		{
			JRigidBody body = targetObject.Physics.RigidBody;

			distance = body.DistanceToPoint(camera.Transform.Position, ref contactPoint, ref normal);

			if (distance == -1) sphereContactPoint.Hide = true;
			else
			{
				sphereContactPoint.Hide = false;
				sphereContactPoint.Transform.Position = contactPoint;
			}
		}

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

			// Render the Jad.Scene using the scene camera
			backbuffer.Render();

			if (showHelp)
			{
				// Get access to the 1st font. The engine creates a font by default
				JFont font = Jad.Video.Fonts[0];

				Jad.Video.Fonts.Begin();

				font.RenderLine(Jad.Version + ". Press ESC to exit. Press G to Show/Hide Gizmos. F1 show/hide text", 0, JColor.Yellow);

				font.RenderLine(Jad.Video.Views.CurrentView.Stats.Fps + " FPS", 0, JColor.White);

				font.RenderLine("World Collision(C): " + camera.UseWorldColision.ToString(), 0, JColor.White);

				font.RenderLine("Min. Distance to Hebe: " + distance.ToString("N2") + " Contact point:" + JMath.Vector3ToString(contactPoint) + " Normal:" + JMath.Vector3ToString(normal), 0, JColor.White);

				Jad.Video.Fonts.End();
			}

			// Show the backbuffer
			backbuffer.Present();
		}

		#endregion
	}
}

Last edited Mar 8, 2007 at 7:51 PM by Vicente, version 5

Comments

No comments yet.