#### Transform ray position to terrain heightmap texture space

Hi guys

I have a multitextured terrain which Ive been using as a learning platform(collision detection, etc..)
and the next thing I would like to do is have a ray shoot through the terrain returning the coordinates
of whatever texture was intersected in order to finish up the particles effect of water splashes and dirt debris. I was given some info on how to do this in two steps, one was to transform the ray into object space and two to then transform the ray into the texture space of the terrain Ive finished the first step but Im having trouble on finding a sample of the ray into texture space using XNA/c# if anyone could point me in the right direction on solving this problem it would be much appreciated(code I have so far is below)

Thankyou

the ray code

Code:
`01	public Ray CalculateRay(Vector2 mouseLocation, Matrix view, 02	          Matrix projection, Viewport viewport) 03	     { 04	         Vector3 nearPoint = viewport.Unproject(new Vector3(mouseLocation.X, 05	                mouseLocation.Y, 0f), 06	                projection, 07	                view, 08	                Matrix.Identity); 09	  10	         Vector3 farPoint = viewport.Unproject(new Vector3(mouseLocation.X, 11	                 mouseLocation.Y, 1f), 12	                 projection, 13	                 view, 14	                 Matrix.Identity); 15	  16	         direction = farPoint - nearPoint; 17	         direction.Normalize(); 18	  19	         Matrix inverseTransform1 = Matrix.Invert(view); 20	         Vector3 nearpoint1 = Vector3.Transform(nearPoint, inverseTransform1); 21	         Vector3 direction1 = Vector3.Transform(direction, inverseTransform1); 22	         return new Ray(nearpoint1, direction1); 23	     }`

the terrain class

Code:
`001	using System; 002	using System.Collections.Generic; 003	using Microsoft.Xna.Framework; 004	using Microsoft.Xna.Framework.Audio; 005	using Microsoft.Xna.Framework.Content; 006	using Microsoft.Xna.Framework.GamerServices; 007	using Microsoft.Xna.Framework.Graphics; 008	using Microsoft.Xna.Framework.Input; 009	using Microsoft.Xna.Framework.Net; 010	using Microsoft.Xna.Framework.Storage; 011	  012	namespace TerrainProject 013	{ 014	    public class Terrain 015	    { 016	        /* 017	         * Struct to hold vertex information with pos,normal,texcoord and texweight 018	         */ 019	        public struct VertexMultitextured 020	        { 021	            public Vector3 Position; 022	            public Vector3 Normal; 023	            public Vector4 TextureCoordinate; 024	            public Vector4 TexWeights; 025	  026	            public static int SizeInBytes = (3 + 3 + 4 + 4) * sizeof(float); // vec3 + vec3 + vec4 +vec4 027	            public static VertexElement[] VertexElements = new VertexElement[] 028	            { 029	                // stream, offset, type, method, usage and usage index 030	                new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0 ), 031	                new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0 ), 032	                new VertexElement( 0, sizeof(float) * 6, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0 ), 033	                new VertexElement( 0, sizeof(float) * 10, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 1 ), 034	            }; 035	        } 036	  037	        Game1 GameClass; 038	        GraphicsDevice device; 039	  040	        int terrainWidth; 041	        int terrainLength; 042	        public float[,] heightData; 043	  044	        VertexBuffer terrainVertexBuffer; 045	        IndexBuffer terrainIndexBuffer; 046	        VertexDeclaration terrainVertexDeclaration; 047	  048	        Texture2D grassTexture; 049	        Texture2D sandTexture; 050	        Texture2D rockTexture; 051	        Texture2D snowTexture; 052	  053	        public Terrain(Game1 reference,GraphicsDevice device) 054	        { 055	            this.GameClass = reference; 056	            this.device = device; 057	  058	            LoadVertices(); 059	            LoadTextures(); 060	        } 061	  062	        private void LoadTextures() 063	        { 064	            grassTexture = GameClass.Content.Load<Texture2D>("grass"); 065	            sandTexture = GameClass.Content.Load<Texture2D>("sand"); 066	            rockTexture = GameClass.Content.Load<Texture2D>("rock"); 067	            snowTexture = GameClass.Content.Load<Texture2D>("snow"); 068	        } 069	  070	        private void LoadVertices() 071	        { 072	  073	            Texture2D heightMap = GameClass.Content.Load<Texture2D>("heightmap"); 074	            LoadHeightData(heightMap); 075	  076	            VertexMultitextured[] terrainVertices = SetUpTerrainVertices(); 077	            int[] terrainIndices = SetUpTerrainIndices(); 078	            terrainVertices = CalculateNormals(terrainVertices, terrainIndices); 079	            CopyToTerrainBuffers(terrainVertices, terrainIndices); 080	            terrainVertexDeclaration = new VertexDeclaration(device, VertexMultitextured.VertexElements); 081	        } 082	  083	        private void LoadHeightData(Texture2D heightMap) 084	        { 085	            float minimumHeight = float.MaxValue; 086	            float maximumHeight = float.MinValue; 087	  088	            terrainWidth = heightMap.Width; 089	            terrainLength = heightMap.Height; 090	  091	            // get rgb values for each pixel of hightmap 092	            Color[] heightMapColors = new Color[terrainWidth * terrainLength]; 093	            heightMap.GetData(heightMapColors); 094	  095	            heightData = new float[terrainWidth, terrainLength]; 096	            for (int x = 0; x < terrainWidth; x++) 097	                for (int y = 0; y < terrainLength; y++) 098	                { 099	                    heightData[x, y] = heightMapColors[x + (y * terrainWidth)].R; // read r value 100	                    // determine minimum and maximum height value in terrain 101	                    if (heightData[x, y] < minimumHeight) minimumHeight = heightData[x, y]; 102	                    if (heightData[x, y] > maximumHeight) maximumHeight = heightData[x, y]; 103	                } 104	  105	            // get height values in a range between 0 and 30 106	            for (int x = 0; x < terrainWidth; x++) 107	                for (int y = 0; y < terrainLength; y++) 108	                    heightData[x, y] = (heightData[x, y] - minimumHeight) / (maximumHeight - minimumHeight) * 30.0f; 109	  110	        } 111	  112	        /* 113	         * Define Vertices 114	         */ 115	        private VertexMultitextured[] SetUpTerrainVertices() 116	        { 117	            VertexMultitextured[] terrainVertices = new VertexMultitextured[terrainWidth * terrainLength]; 118	  119	            for (int x = 0; x < terrainWidth; x++) 120	            { 121	                for (int y = 0; y < terrainLength; y++) 122	                { 123	                    // generate a vertex for each pixel of the heightmap 124	                    // a terrain is generated in x,-y direction 125	                    terrainVertices[x + (y * terrainWidth)].Position = new Vector3(x, heightData[x, y], -y); 126	                    terrainVertices[x + (y * terrainWidth)].TextureCoordinate.X = (float)x / 30.0f; // /30 to stretch texture so it looks realistic 127	                    terrainVertices[x + (y * terrainWidth)].TextureCoordinate.Y = (float)y / 30.0f; 128	  129	                    /* 130	                     * A vertex with height 12 should have texweight 1. 131	                     * The weight should become 0 for heights 6 and 18, which are 12-6 and 12+6. In other words: all heights that 132	                     * are within 6 meters from 12 meter high should have a weight factor for the grass texture. This explains the 133	                     * ‘abs(height-12)/6’: it will be 0 for height = 12, and become 1 as height approaches 6 or 18. But we need 134	                     * the opposite: at height 12 we need weight=1, and at heights 6 and 12 we need weight 0. So we subtract our 135	                     * line above from 1 and get ‘1- abs(height-12)/6’. This will become smaller than 0 for height lower than 6 136	                     * and larger than 18, so we clamp this value between 0 and 1. 137	                     * Although this is a step in the good direction, it isn’t perfect yet. For example: as their snow and 138	                     * rock weights are 0.2, the pixels corresponding to height 25 will get 20% of their color from the snow 139	                     * texture, and 20% from the rock texture. The remaining 60% will remain black, so they will look very dark. 140	                     * To solve this, we must make sure that for every vertex, the sum of all weights is exactly 1. 141	                     * To do this, for each vertex we’ll make the sum of all weights, and divide all weights by this sum. In case 142	                     * of the previous example, the sum would be 0.2 + 0.2 = 0.4. Next, 0.2 divided by 0.4 gives 0.5 for both the 143	                     * new snow and rock weights. And of course, 0.5 + 0.5 equals 1. This is what is shown in the right part 144	                     * of the image above. You’ll notice that for each height, the summed weight value is 1. 145	                     */ 146	  147	                    // X = Sand, Y = Grass, Z = Stone and W = Snow 148	                    terrainVertices[x + (y * terrainWidth)].TexWeights.X = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 0) / 8.0f, 0, 1); 149	                    terrainVertices[x + (y * terrainWidth)].TexWeights.Y = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 12) / 6.0f, 0, 1); 150	                    terrainVertices[x + (y * terrainWidth)].TexWeights.Z = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 20) / 6.0f, 0, 1); 151	                    terrainVertices[x + (y * terrainWidth)].TexWeights.W = MathHelper.Clamp(1.0f - Math.Abs(heightData[x, y] - 30) / 6.0f, 0, 1); 152	  153	                    float total = terrainVertices[x + y * terrainWidth].TexWeights.X; 154	                    total += terrainVertices[x + y * terrainWidth].TexWeights.Y; 155	                    total += terrainVertices[x + y * terrainWidth].TexWeights.Z; 156	                    total += terrainVertices[x + y * terrainWidth].TexWeights.W; 157	  158	                    terrainVertices[x + y * terrainWidth].TexWeights.X /= total; 159	                    terrainVertices[x + y * terrainWidth].TexWeights.Y /= total; 160	                    terrainVertices[x + y * terrainWidth].TexWeights.Z /= total; 161	                    terrainVertices[x + y * terrainWidth].TexWeights.W /= total; 162	                } 163	            } 164	  165	            return terrainVertices; 166	        } 167	  168	        /* 169	         * Set indices clockwise to build faces 170	         */ 171	        private int[] SetUpTerrainIndices() 172	        { 173	            /* 174	             * new int[(terrainWidth - 1) * (terrainLength - 1) * 6] 175	             * Example, plane consisting of 4x3 points: first row is build out of 3 quads, second one also. 176	             *                                        row   col    3 points are needed for each triangle, 6 for one quad 177	             * so for a 4x3 points plane one can say (4-1)*(3-1) * 6 178	             */ 179	            int[] indices = new int[(terrainWidth - 1) * (terrainLength - 1) * 6]; 180	            int counter = 0; 181	            for (int y = 0; y < terrainLength - 1; y++) 182	            { 183	                for (int x = 0; x < terrainWidth - 1; x++) 184	                { 185	                    int lowerLeft = x + y * terrainWidth; 186	                    int lowerRight = (x + 1) + y * terrainWidth; 187	                    int topLeft = x + (y + 1) * terrainWidth; 188	                    int topRight = (x + 1) + (y + 1) * terrainWidth; 189	  190	                    // order clockwise 191	                    indices[counter++] = topLeft; 192	                    indices[counter++] = lowerRight; 193	                    indices[counter++] = lowerLeft; 194	  195	                    indices[counter++] = topLeft; 196	                    indices[counter++] = topRight; 197	                    indices[counter++] = lowerRight; 198	                } 199	            } 200	  201	            return indices; 202	        } 203	  204	        /* 205	         * Calculate Normals on Terrain for realistic shadows 206	         */ 207	        private VertexMultitextured[] CalculateNormals(VertexMultitextured[] vertices, int[] indices) 208	        { 209	            // initialise normals with 0 0 0 210	            for (int i = 0; i < vertices.Length; i++) 211	                vertices[i].Normal = new Vector3(0, 0, 0); 212	  213	            for (int i = 0; i < indices.Length / 3; i++) 214	            { 215	                // Calculate Triangle 216	                int index1 = indices[i * 3]; 217	                int index2 = indices[i * 3 + 1]; 218	                int index3 = indices[i * 3 + 2]; 219	  220	                // Calculate normal on triangle 221	                Vector3 side1 = vertices[index1].Position - vertices[index3].Position; 222	                Vector3 side2 = vertices[index1].Position - vertices[index2].Position; 223	                Vector3 normal = Vector3.Cross(side1, side2); 224	  225	                // apply normal on all three vertices of triangle 226	                vertices[index1].Normal += normal; 227	                vertices[index2].Normal += normal; 228	                vertices[index3].Normal += normal; 229	            } 230	  231	            // normalize all normals 232	            for (int i = 0; i < vertices.Length; i++) 233	                vertices[i].Normal.Normalize(); 234	  235	            return vertices; 236	        } 237	  238	        /* 239	         * Copy vertices and indices onto grafikcard buffer to save performance (so this data has to be transferred ONLY ONCE) 240	         */ 241	        private void CopyToTerrainBuffers(VertexMultitextured[] vertices, int[] indices) 242	        { 243	            terrainVertexBuffer = new VertexBuffer(device, vertices.Length * VertexMultitextured.SizeInBytes, BufferUsage.WriteOnly); 244	            terrainVertexBuffer.SetData(vertices); 245	  246	            terrainIndexBuffer = new IndexBuffer(device, typeof(int), indices.Length, BufferUsage.WriteOnly); 247	            terrainIndexBuffer.SetData(indices); 248	        } 249	  250	        /* 251	         * This draws the terrain 252	         */ 253	        public void DrawTerrain(Effect effect) 254	        { 255	            effect.CurrentTechnique = effect.Techniques["MultiTextured"]; 256	            effect.Parameters["xTexture0"].SetValue(sandTexture); 257	            effect.Parameters["xTexture1"].SetValue(grassTexture); 258	            effect.Parameters["xTexture2"].SetValue(rockTexture); 259	            effect.Parameters["xTexture3"].SetValue(snowTexture); 260	  261	            Matrix worldMatrix = Matrix.Identity; 262	            effect.Parameters["xWorld"].SetValue(worldMatrix); 263	            effect.Parameters["xEnableLighting"].SetValue(true); 264	            effect.Parameters["xAmbient"].SetValue(0.4f); 265	            effect.Parameters["xLightDirection"].SetValue(new Vector3(-0.5f, -1, -0.5f)); 266	  267	            effect.Begin(); 268	            foreach (EffectPass pass in effect.CurrentTechnique.Passes) 269	            { 270	                pass.Begin(); 271	  272	                device.Vertices[0].SetSource(terrainVertexBuffer, 0, VertexMultitextured.SizeInBytes); // tell it that this data is in graka buffer 273	                device.Indices = terrainIndexBuffer; 274	                device.VertexDeclaration = terrainVertexDeclaration; 275	  276	                int noVertices = terrainVertexBuffer.SizeInBytes / VertexMultitextured.SizeInBytes; 277	                int noTriangles = terrainIndexBuffer.SizeInBytes / sizeof(int) / 3; 278	                device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, noVertices, 0, noTriangles); 279	  280	                pass.End(); 281	            } 282	            effect.End(); 283	        } 284	  285	    } 286	}`