Object picking with Ray casting in elm-webgl -
demo (?) working example: https://ellie-app.com/4h9f8fncrpya1/1
demo: click draw ray, , rotate camera left , right see ray. (as origin camera, can't see position created)
context
working on elm & elm-webgl project know if mouse on object when clicked. tried implement simple ray cast. need 2 things:
1) coordinate of camera (this 1 easy)
2) coordinate/direction in 3d space of clicked
problem
steps 2d view space 3d world space understand are:
a) make coordinates in range of -1 1 relative view port
b) invert projection matrix , perspective matrix
c) multiply projection , perspective matrix
d) create vector4 normalised mouse coordinates
e) multiply combined matrices vector4
f) normalise result
try far
have made function transform mouse.position coordinate draw line to:
getclickposition : model -> mouse.position -> 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 = vec4.vec4 (tuple.first normalizedposition) (tuple.second normalizedposition) 1 1 toinversed = mulvector inversedmatrix2 tonorm = vec4.normalize toinversed tovec3 = vec3 (vec4.getx tonorm) (vec4.gety tonorm) (vec4.getz tonorm) in tovec3
result
result of function rays center click. added screenshot clicked in 4 of top face of cube. if click on center of viewport ray correctly positioned.
it feels close, not quite there yet , can't figure out doing wrong!
after trying other approaches found solution:
getclickposition : model -> mouse.position -> 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 inversedviewmatrix = maybe.withdefault mat4.identity (mat4.inverse (camera model)) inversedprojectionmatrix = maybe.withdefault mat4.identity (mat4.inverse perspective) vec4cameracoordinates = mulvector inversedprojectionmatrix homogeneousclipcoordinates direction = vec4.vec4 (vec4.getx vec4cameracoordinates) (vec4.gety vec4cameracoordinates) -1 0 vec4worldcoordinates = mulvector inversedviewmatrix direction vec3worldcoordinates = vec3 (vec4.getx vec4worldcoordinates) (vec4.gety vec4worldcoordinates) (vec4.getz vec4worldcoordinates) normalizedvec3worldcoordinates = vec3.normalize vec3worldcoordinates origin = model.camerapos scaleddirection = vec3.scale 20 normalizedvec3worldcoordinates destination = vec3.add origin scaleddirection in destination
i left verbose possible, if finds use incorrect terminology please make comment , update answer.
i sure there lots of optimisations possible (multiplying matrices before inverting or combining of steps.)
updated ellie app here: https://ellie-app.com/4hz9s8s92psa1/0
Comments
Post a Comment