title: Object picking with Ray casting in elm-webgl
body: <p>Demo almost (?) working example: <a href="https://ellie-app.com/4h9F8FNcRPya1/1" rel="nofollow noreferrer">https://ellie-app.com/4h9F8FNcRPya1/1</a><br>
  For demo: Click to draw ray, and rotate camera with left and right to see ray. (As the origin is from the camera, you can't see it from the position it is created)</p>
  
  <p><strong>Context</strong><br>
  I am working on an elm &amp; elm-webgl project where I would like to know if the mouse is over an object when clicked. To do is I tried to implement a simple ray cast. What I need is two things:<br>
  1) The coordinate of the camera (This one is easy)<br>
  2) The coordinate/direction in 3D space of where was clicked</p>
  
  <p><strong>Problem</strong><br>
  The steps to get from 2D view space to 3D world space as I understand are:<br>
  a) Make coordinates to be in a range of -1 to 1 relative to view port<br>
  b) Invert projection matrix and perspective matrix<br>
  c) Multiply projection and perspective matrix<br>
  d) Create Vector4 from normalised mouse coordinates<br>
  e) Multiply combined matrices with Vector4<br>
  f) Normalise result </p>
  
  <p><strong>Try so far</strong><br>
  I have made a function to transform a Mouse.Position to a coordinate to draw a line to:</p>
  
  <pre><code>getClickPosition : Model -&gt; Mouse.Position -&gt; Vec3
  getClickPosition model pos =
      let
          x =
              toFloat pos.x
  
          y =
              toFloat pos.y
  
          normalizedPosition =
              ( (x * 2) / 1000 - 1, (1 - y / 1000 * 2) )
  
          homogeneousClipCoordinates =
              Vec4.vec4
                  (Tuple.first normalizedPosition)
                  (Tuple.second normalizedPosition)
                  -1
                  1
  
          inversedProjectionMatrix =
              Maybe.withDefault Mat4.identity (Mat4.inverse (camera model))
  
          inversedPerspectiveMatrix =
              Maybe.withDefault Mat4.identity (Mat4.inverse perspective)
  
          inversedMatrix2 =
              Mat4.mul inversedProjectionMatrix inversedPerspectiveMatrix
  
          to =
              Vec4.vec4
                  (Tuple.first normalizedPosition)
                  (Tuple.second normalizedPosition)
                  1
                  1
  
          toInversed =
              mulVector inversedMatrix2 to
  
          toNorm =
              Vec4.normalize toInversed
  
          toVec3 =
              vec3 (Vec4.getX toNorm) (Vec4.getY toNorm) (Vec4.getZ toNorm)
      in
          toVec3
  </code></pre>
  
  <p><strong>Result</strong><br>
  The result of this function is that the rays are too much to the center to where I click. I added a screenshot where I clicked in all four of the top face of the cube. If I click on the center of the viewport the ray will be correctly positioned.</p>
  
  <p>It feels close, but not quite there yet and I can't figure out what I am doing wrong!</p>
  
  <p><a href="https://i.stack.imgur.com/uo2mz.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/uo2mz.png" alt="Example image of current situation"></a></p>