my code works fine for plane surface

but i have terrain which has a plane in middle and some mountains on side

Image attached below will tell you more

using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using JigLibX.Math; using JigLibX.Physics; using JigLibX.Geometry; namespace RacerX { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; RasterizerState rs; SpriteBatch spriteBatch; Model terrain; Model car; Model WheelfrontRight; Vector3 frontRightWheelPos = new Vector3(1.8f, 0.4f, 1.0f); Model WheelfrontLeft; Model WheelbackRight; Model WheelbackLeft; Vector3 cameraPosition = new Vector3(0.0f, 10.0f, 20.0f); Vector3 cameraLookAt; float angle = 0.0f; Vector3 rayDir; float speed; Vector3 vertex1, vertex2, vertex3; List<string> insideBoundingSpheres = new List<string>(); Matrix cameraViewMatrix; Matrix cameraProjectionMatrix; Matrix wheelMatrix; Matrix terrainWorldMatrix; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); rs = new RasterizerState(); rs.FillMode = FillMode.WireFrame; graphics.GraphicsDevice.RasterizerState = rs; terrain = Content.Load<Model>("terrain"); terrainWorldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix.CreateTranslation(Vector3.Zero); car = Content.Load<Model>("car"); WheelfrontRight=Content.Load<Model>("wheel"); WheelfrontLeft = Content.Load<Model>("wheel"); WheelbackRight = Content.Load<Model>("wheel"); WheelbackLeft = Content.Load<Model>("wheel"); wheelMatrix = Matrix.CreateTranslation(frontRightWheelPos); rayDir = Vector3.Down; speed = 0.025f; // TODO: use this.Content to load your game content here } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit cameraLookAt = frontRightWheelPos; cameraViewMatrix = Matrix.CreateLookAt(cameraPosition, cameraLookAt, Vector3.Up); cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), graphics.GraphicsDevice.Viewport.AspectRatio, 1.0f, 10000.0f); KeyboardState keyboard = Keyboard.GetState(); if(keyboard.IsKeyDown(Keys.Up)) { angle += 2.0f; if (angle == 360.0f) { angle = 0.0f; } else { frontRightWheelPos.X += speed; rayDir.X += speed; cameraPosition.X += speed; wheelMatrix = Matrix.Identity * Matrix.CreateRotationZ(MathHelper.ToRadians(-angle)) * Matrix.CreateTranslation(frontRightWheelPos); } } if(keyboard.IsKeyDown(Keys.Down)) { angle -= 2.0f; if (angle == 360.0f) { angle = 0.0f; } else { frontRightWheelPos.X -= speed; rayDir.X -= speed; cameraPosition.X -= speed; wheelMatrix = Matrix.Identity * Matrix.CreateRotationZ(MathHelper.ToRadians(-angle)) * Matrix.CreateTranslation(frontRightWheelPos); } } // TODO: Add your update logic here UpdatePicking(); //this.Update(gameTime); base.Update(gameTime); } #region CollisionDetection void UpdatePicking() { // Look up a collision ray based on the current cursor position. See the // Picking Sample documentation for a detailed explanation of this. Microsoft.Xna.Framework.Ray wheelRay; wheelRay.Direction = rayDir; wheelRay.Position = frontRightWheelPos; insideBoundingSpheres.Clear(); bool insideBoundingSphere; // Perform the ray to model intersection test. float? intersection = RayIntersectsModel(wheelRay, terrain, Matrix.CreateTranslation(Vector3.Zero), out insideBoundingSphere, out vertex1, out vertex2, out vertex3); // If this model passed the initial bounding sphere test, remember // that so we can display it at the top of the screen. if (insideBoundingSphere) insideBoundingSpheres.Add("terrain"); Vector3 triNormal; Vector3 vN1 = Vector3.Subtract(vertex2, vertex1); Vector3 vN2 = Vector3.Subtract(vertex3, vertex2); triNormal = Vector3.Cross(vN1, vN2); float d; d = -Vector3.Dot(vertex1, triNormal); Vector3 ray; ray = Vector3.Subtract(rayDir, frontRightWheelPos); Vector3.Normalize(ray); float time = -(d + Vector3.Dot(triNormal, frontRightWheelPos)) / Vector3.Dot(triNormal, ray); Vector3 intersect = frontRightWheelPos + (ray * time); if (intersection != null) { frontRightWheelPos.Y = intersect.Y + .4f; } else { wheelRay.Position = new Vector3(frontRightWheelPos.X, 10.0f, frontRightWheelPos.Z); } if (float.IsNaN(intersect.Y)) { //System.Diagnostics.Debugger.Break(); } } static float? RayIntersectsModel(Microsoft.Xna.Framework.Ray ray, Model model, Matrix modelTransform, out bool insideBoundingSphere, out Vector3 vertex1, out Vector3 vertex2, out Vector3 vertex3) { vertex1 = vertex2 = vertex3 = Vector3.Zero; Matrix inverseTransform = Matrix.Invert(modelTransform); ray.Position = Vector3.Transform(ray.Position, inverseTransform); ray.Direction = Vector3.TransformNormal(ray.Direction, inverseTransform); // Look up our custom collision data from the Tag property of the model. Dictionary<string, object> tagData = (Dictionary<string, object>)model.Tag; if (tagData == null) { throw new InvalidOperationException( "Model.Tag is not set correctly. Make sure your model " + "was built using the custom TrianglePickingProcessor."); } // Start off with a fast bounding sphere test. BoundingSphere boundingSphere = (BoundingSphere)tagData["BoundingSphere"]; if (boundingSphere.Intersects(ray) == null) { // If the ray does not intersect the bounding sphere, we cannot // possibly have picked this model, so there is no need to even // bother looking at the individual triangle data. insideBoundingSphere = false; //System.Diagnostics.Debugger.Break(); return null; } else { // The bounding sphere test passed, so we need to do a full // triangle picking test. insideBoundingSphere = true; // Keep track of the closest triangle we found so far, // so we can always return the closest one. float? closestIntersection = null; // Loop over the vertex data, 3 at a time (3 vertices = 1 triangle). Vector3[] vertices = (Vector3[])tagData["Vertices"]; for (int i = 0; i < vertices.Length; i += 3) { // Perform a ray to triangle intersection test. float? intersection; RayIntersectsTriangle(ref ray, ref vertices[i], ref vertices[i + 1], ref vertices[i + 2], out intersection); // Does the ray intersect this triangle? if (intersection != null) { // If so, is it closer than any other previous triangle? if ((closestIntersection == null) || (intersection < closestIntersection)) { // Store the distance to this triangle. closestIntersection = intersection; // Transform the three vertex positions into world space, // and store them into the output vertex parameters. Vector3.Transform(ref vertices[i], ref modelTransform, out vertex1); Vector3.Transform(ref vertices[i + 1], ref modelTransform, out vertex2); Vector3.Transform(ref vertices[i + 2], ref modelTransform, out vertex3); } } } return closestIntersection; } } static void RayIntersectsTriangle(ref Microsoft.Xna.Framework.Ray ray, ref Vector3 vertex1, ref Vector3 vertex2, ref Vector3 vertex3, out float? result) { // Compute vectors along two edges of the triangle. Vector3 edge1, edge2; Vector3.Subtract(ref vertex2, ref vertex1, out edge1); Vector3.Subtract(ref vertex3, ref vertex1, out edge2); // Compute the determinant. Vector3 directionCrossEdge2; Vector3.Cross(ref ray.Direction, ref edge2, out directionCrossEdge2); float determinant; Vector3.Dot(ref edge1, ref directionCrossEdge2, out determinant); // If the ray is parallel to the triangle plane, there is no collision. if (determinant > -float.Epsilon && determinant < float.Epsilon) { result = null; return; } float inverseDeterminant = 1.0f / determinant; // Calculate the U parameter of the intersection point. Vector3 distanceVector; Vector3.Subtract(ref ray.Position, ref vertex1, out distanceVector); float triangleU; Vector3.Dot(ref distanceVector, ref directionCrossEdge2, out triangleU); triangleU *= inverseDeterminant; // Make sure it is inside the triangle. if (triangleU < 0 || triangleU > 1) { result = null; return; } // Calculate the V parameter of the intersection point. Vector3 distanceCrossEdge1; Vector3.Cross(ref distanceVector, ref edge1, out distanceCrossEdge1); float triangleV; Vector3.Dot(ref ray.Direction, ref distanceCrossEdge1, out triangleV); triangleV *= inverseDeterminant; // Make sure it is inside the triangle. if (triangleV < 0 || triangleU + triangleV > 1) { result = null; return; } // Compute the distance along the ray to the triangle. float rayDistance; Vector3.Dot(ref edge2, ref distanceCrossEdge1, out rayDistance); rayDistance *= inverseDeterminant; // Is the triangle behind the ray origin? if (rayDistance < 0) { result = null; return; } result = rayDistance; } #endregion /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); LoadTerrain(); // TODO: Add your drawing code here DrawModel(car, new Vector3(0.0f,0.1f,0.0f)); CreateWheels(WheelfrontRight, wheelMatrix); base.Draw(gameTime); } void DrawModel(Model model,Vector3 Position) { foreach (ModelMesh mesh in model.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.PreferPerPixelLighting = true; effect.World = Matrix.CreateTranslation(Position); effect.Projection = cameraProjectionMatrix; effect.View = cameraViewMatrix; } mesh.Draw(); } } void CreateWheels(Model wheelModel, Matrix wheelMatrix) { foreach (ModelMesh mesh in wheelModel.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.PreferPerPixelLighting = true; effect.DirectionalLight0.Direction = Vector3.Down; effect.World = wheelMatrix; effect.Projection = cameraProjectionMatrix; effect.View = cameraViewMatrix; } mesh.Draw(); } } void LoadTerrain() { Matrix terrainWorldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix.CreateTranslation(Vector3.Zero); foreach (ModelMesh mesh in terrain.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.PreferPerPixelLighting = true; effect.DirectionalLight0.Direction = Vector3.Down; effect.World = terrainWorldMatrix; effect.Projection = cameraProjectionMatrix; effect.View = cameraViewMatrix; } mesh.Draw(); } } } }

Thanks for any help you provide