Mapping mouseclick on 3DModel to a 2D texture coordinate
Some time back I posted a gadget with the rotating earth. This looked nice but it lacked some interaction. One of the things to make it interactive was to map the point of clicking to the texture applied on the globe. To get the 2D coordinate we need to perform a hittest on the Viewport3D and this will give us access to RayMeshGeometry3DHitTestResult object. This provides info on the mesh, geometrymodel, vertex indices of the triangle hit, and the barycentric coordinates. To obtain the coordinate we multiply the vertex weights (barycentric coordinates) with the cordinates of the triangle hit. We then scale this point with the texture size to get the actual pixel within the texture (The link to the barycentric coordinates is a nice read and explains the math behind these calculations).
The image below is the same rotating globe but which shows the continent name when clicked on the globe.. The continent boundaries are not exact - so you might see some land not being mapped to anything ;).. A red dot indicates the mouse point/click
The code (by Kurt Berglund) looks something like the below:
1 public HitTestResultBehavior HTResult(System.Windows.Media.HitTestResult rawresult)
2 {
3 RayHitTestResult rayResult = rawresult as RayHitTestResult;
4
5 if (rayResult != null)
6 {
7 RayMeshGeometry3DHitTestResult rayMeshResult = rayResult as RayMeshGeometry3DHitTestResult;
8 if (rayMeshResult != null)
9 {
10 GeometryModel3D hitgeo = rayMeshResult.ModelHit as GeometryModel3D;
11 MeshGeometry3D geom = rayMeshResult.MeshHit;
12
13 // pull the barycentric coordinates of the intersection point
14 double vertexWeight1 = rayMeshResult.VertexWeight1;
15 double vertexWeight2 = rayMeshResult.VertexWeight2;
16 double vertexWeight3 = rayMeshResult.VertexWeight3;
17
18 // the indices in to where the actual intersection occurred
19 int index1 = rayMeshResult.VertexIndex1;
20 int index2 = rayMeshResult.VertexIndex2;
21 int index3 = rayMeshResult.VertexIndex3;
22
23 // texture coordinates of the three vertices hit
24 Point texCoord1 = geom.TextureCoordinates[index1];
25 Point texCoord2 = geom.TextureCoordinates[index2];
26 Point texCoord3 = geom.TextureCoordinates[index3];
27
28 // get the final uv values based on the barycentric coordinates
29 Point finalPoint = new Point(texCoord1.X * vertexWeight1 +
30 texCoord2.X * vertexWeight2 +
31 texCoord3.X * vertexWeight3,
32 texCoord1.Y * vertexWeight1 +
33 texCoord2.Y * vertexWeight2 +
34 texCoord3.Y * vertexWeight3);
35
36 MessageBox.Show(finalPoint.ToString());
37 //Multiply the final point with the texture size
38
39 }
40 }
41
42 return HitTestResultBehavior.Continue;
43 }
Sample project is attached :)
Comments
- Anonymous
December 03, 2006
This is just plain cool and I had to link to it before I pack. Lester Lobo has posted a great little