Implement ray picking object with OpenGL

xiaoxiao2021-03-06  59

Regarding the use of ray principles, it has been picked up on the Internet already has a complete theory. In addition, DirectX also provides a PICK example to demonstrate, here I have a slight summary of these materials and theories and give full implementation under OpenGL.

The relevant theory is generally from an English data and a summary Chinese information, respectively:

http://www.gameres.com/articles/program/visual/3d/pick_2004_529.htm

http://www.mvps.org/directx/Articles/rayproj.htm

The previous story tells the principle and implementation of ray picking objects with DirectX. The latter story is the conversion principle of two-dimensional screen space to 3D world space. The previous name is "Direct3D's mouse picking", which is very good. The latter article describes the principles of ray formation, and there is an example of the source code.

The following will be implemented on OpenGL.

Step 1: Implement the conversion of the screen coordinates to the 3D world space coordinates, in this step OpenGL is more simple than DirectX, using the function GluunProject can get the three-dimensional space coordinates of the screen coordinates, examples: GluunProject ((GLDOUBLE) XPOS, (GLDOUBLE) YPOS, 1.0, MVMatrix, Projmatrix, ViewPort, & WX, & Wy, & WZ); XPOS and YPOS are screen coordinates of origin as the origin in the lower left corner of the screen, 1.0 represents the world of zbuffer is 1.0 (remote cutting point) coordinates, mvmatrix matrix for visually by GetDoublev (GL_MODELVIEW_MATRIX, mvmatrix) to give, projmatrix projection matrix obtained by glGetDoublev (GL_PROJECTION_MATRIX, projmatrix), viewport viewport, obtained by glGetIntegerv (GL_VIEWPORT, viewport), the remaining wx, wy WZ is the world coordinates we have to get, getting two world coordinates, rays are determined, or you can use the origin (viewpoint) to replace one of them, because this ray is from the viewpoint. Step 2: Use rays and triangles to be detected to integrate, the principles and formulas used are as follows. Principle 1: Any point in the triangle can be determined using variables u, v and its three vertex coordinates, of which 0

(-Dir.x) * LEN (V2.x-v1.x) * U (v3.x - v1.x) * v = OriginPoint.x -v1.x (-dir.y) * len ( V2.y-v1.y) * u (v3.y - v1.y) * v = OriginPoint.y -v1.y (-dir.z) * LEN (V2.z-v1.z) * U (V3.z - v1.z) * v = OriginPoint.z -v1.z or: LEN [-dir, V2-V1, V3-V1] {u} = OriginPoint - V1 V This is a linear equation, According to the Kramfa, [- DIR, V2-V1, V3-V1] is not zero. Therefore, conditions: 0 0, 0

Pseudo code implementation (principle is implemented in the DirectX PICK example): // triangular two side of the vector vector3 EDGE1 = V1 - V0; Vctor3 EDGE2 = V2 - V0; Vctor3 PVEC; VEC3CROSS (& PVEC, & DIR, & EDGE2); / / Differential float DET = VEC3DOT (& Edge1, & PVEC); // Dumotive // ​​DET Its Meaning is [-Dir, V2-V1, V3-V1] matrix expands Vector3 TVEC; IF (DET> 0) // {TVEC = ORIG - V0; // From the front cross-triangular, triangular and viewpoint faces on the front} else {tvec = V0 - orig; // Cross the triangle cross the triangle Det = -det;} IF (DET <0.0001F) / / Access to zero is considered to be 0 return false; / / find the value of U, the discharge of the linear equation group is equivalent to the spot exhibition * u = VEC3DOT (& tvec, & pVEC); if (* u <0.0f || * u> DET) Return false; // Require V. Vector3 QVEC; VEC3CROS (& QVEC, & TVEC, & EDGE1); * v = vec3dot (& Dir, & Dir, & qVEC); if (* v <0.0f || * u * v> DET) RETURN FALSE; / / Calculate T and confuse T, U, V as legitimate * T = D3DXVEC3DOT (& Edge2, & QVEC); // front T, V, u Take a coefficient Detfloat when calculating FINVDET = 1.0f / DET; * t * = finvdet; * u * = finvdet; * v * = finvdet; // Here this algorithm is given by Microsoft, from geometric perspective, it is very difficult to understand, the real method is According to the linear equation lease, it is convinced that the method in the text is in line with the linear equations, which is probably the principle of geometry and algebra.

Source (VC6.0 OpenGL Windows2000, Debug Pass): BOOL INTERSECTTRIANGLE () {GLFLOAT EDGE1 [3]; GLFLOAT EDGE2 [3];

EDGE1 [0] = V1 [0] -V0 [0]; EDGE1 [1] = V1 [1] -V0 [1]; EDGE1 [2] = V1 [2] -V0 [2];

EDGE2 [0] = V2 [0] -V0 [0]; EDGE2 [1] = V2 [1] -V0 [1]; EDGE2 [2] = V2 [2] -V0 [2];

GLFLOAT DIR [3]; DIR [0] = g_farxyz [0] -g_nearxyz [0]; DIR [1] = g_farxyz [1] -g_nearxyz [1]; DIR [2] = g_farxyz [2] -g_nearxyz [2] ;

GLFLOAT W = (GLFLOAT) SQRT (DOUBLE) POW (DIR [0], 2.0) (DOUBLE) POW (DIR [1], 2.0) (DOUBLE) POW (DIR [2], 2.0)); DIR [ 0] / = W; DIR [1] / = W; DIR [2] / = W; GLFLOAT PVEC [3]; PVEC [0] = DIR [1] * Edge2 [2] - DIR [2] * Edge2 [ 1]; PVEC [1] = DIR [2] * Edge2 [0] - DIR [0] * Edge2 [2]; PVEC [2] = DIR [0] * Edge2 [1] - DIR [1] * Edge2 [ 0];

GLFLOAT DET; DET = Edge1 [0] * PVEC [0] EDGE1 [1] * PVEC [1] Edge1 [2] * PVEC [2];

GLFLOAT TVEC [3]; IF (DET> 0) {TVEC [0] = g_nearxyz [0] - V0 [0]; TV [1] = g_nearxyz [1] - v0 [1]; TV [2] = g_nearxyz [ 2] - V0 [2];} else {TVEC [0] = V0 [0] - g_nearxyz [0]; TV [1] = v0 [1] - g_nearxyz [1]; tVEC [2] = v0 [2] - g_nearxyz [2]; DET = -det;} if (DET <0.0001F) Return False;

GLFLOAT U; U = TVEC [0] * PVEC [0] TVEC [1] * PVEC [1] TVEC [2] * PVEC [2]; if (u <0.0f || u> DET) Return False; GLFLOAT QVEC [3]; QVEC [0] = TVEC [1] * Edge1 [2] - TVEC [2] * Edge1 [1]; QVEC [1] = TVEC [2] * Edge1 [0] - TVEC [0] * Edge1 [2]; QVEC [2] = TVEC [0] * Edge1 [1] - TVEC [1] * Edge1 [0]; GLFLOAT V; V = DIR [0] * QVEC [0] DIR [1] * QVEC [1] DIR [2] * QVEC [2]; if (v <0.0f || U V> DET) Return False; GLFLOAT T = Edge2 [0] * QVEC [0] Edge2 [1] * QVEC [1] Edge2 [2] * QVEC [2]; GLFLOAT FINVDET = 1.0F / DET; t * = finvdet; u * = finvdet; v * = finvdet; return

}

Void Pick (GLFLOAT XPOS, GLFLOAT YPOS) {XPOS, YPOS; Glint Viewport [4]; GLDOUBLE MVMATRIX [16], Projmatrix [16]; Glint Realy; GLDOUBLE WX, WY, WZ;

Glgetintegerv (GL_ViewPort, viewport); Glgetdoublev (GL_MODELVIEW_MATRIX, MVMATRIX); GLGETDOUBLEV (GL_Projection_Matrix, Projmatrix);

Realy = viewport [3] - (GLINT) YPOS -1; // Left corner is coordinate original gluunproject (gldouble) XPOS, (GLDOUBLE) Realy, 0.0, MVMatrix, Projmatrix, ViewPort, & WX, & Wy, & WZ); g_nearxyz [ 0] = (GLFLOAT) WX; g_nearxyz [1] = (glfloat) WY; g_nearxyz [2] = (glfloat) WZ;

GluunProject (GLDOUBLE) XPOS, (GLDOUBLE) REAL, 1.0, MVMatrix, Projmatrix, ViewPort, & WX, & Wy, & WZ); g_farxyz [0] = (GLFLOAT) WX; g_farxyz [1] = (GLFLOAT) WY; G_FARXYZ [2 ] = (GLFLOAT) WZ;

g_color = 0.0; IF (intersectTriangle ()) g_color = 1.0;

} GLFLOAT V0 [3] = {1.0, 0.0, -1.0}; GLFLOAT V1 [3] = {0.0, 1.0, -1.0}; GLFLOAT V2 [3] = {0.0, 0.0, -2.0}; Void Drawglscene (GLVOID ) {glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin (GL_TRIANGLES); glColor3f (g_color, 0.0,1.0); glVertex3fv (V0); // if added glTranslatef transform function or the like, should radiation varies inversely glVertex3fv (V1); GlvertEX3FV (V2); glend (); swapbuffers (hdc);

}

This article ends. Email: lzhoumail@126.com, and the DirectX also provides a PICK example to demonstrate, here I have a slight summary of these materials and theories and give full implementation under OpenGL.

The relevant theory is generally from an English data and a summary Chinese information, respectively:

http://www.gameres.com/articles/program/visual/3d/pick_2004_529.htm

http://www.mvps.org/directx/Articles/rayproj.htm

The previous story tells the principle and implementation of ray picking objects with DirectX. The latter story is the conversion principle of two-dimensional screen space to 3D world space. The previous name is "Direct3D's mouse picking", which is very good. The latter article describes the principles of ray formation, and there is an example of the source code.

The following will be implemented on OpenGL.

Step 1: Implement the conversion of the screen coordinates to the 3D world space coordinates, in this step OpenGL is more simple than DirectX, using the function GluunProject can get the three-dimensional space coordinates of the screen coordinates, examples: GluunProject ((GLDOUBLE) XPOS, (GLDOUBLE) YPOS, 1.0, MVMatrix, Projmatrix, ViewPort, & WX, & Wy, & WZ); XPOS and YPOS are screen coordinates of origin as the origin in the lower left corner of the screen, 1.0 represents the world of zbuffer is 1.0 (remote cutting point) coordinates, mvmatrix matrix for visually by GetDoublev (GL_MODELVIEW_MATRIX, mvmatrix) to give, projmatrix projection matrix obtained by glGetDoublev (GL_PROJECTION_MATRIX, projmatrix), viewport viewport, obtained by glGetIntegerv (GL_VIEWPORT, viewport), the remaining wx, wy WZ is the world coordinates we have to get, getting two world coordinates, rays are determined, or you can use the origin (viewpoint) to replace one of them, because this ray is from the viewpoint. Step 2: Use rays and triangles to be detected to integrate, the principles and formulas used are as follows. Principle 1: Any point in the triangle can be determined using variables u, v and its three vertex coordinates, of which 0

(-Dir.x) * LEN (V2.x-v1.x) * U (v3.x - v1.x) * v = OriginPoint.x -v1.x (-dir.y) * len ( V2.y-v1.y) * u (v3.y - v1.y) * v = OriginPoint.y -v1.y (-dir.z) * LEN (V2.z-v1.z) * U (V3.z - v1.z) * v = OriginPoint.z -v1.z or: LEN [-dir, V2-V1, V3-V1] {u} = OriginPoint - V1 V This is a linear equation, According to the Kramfa, [- DIR, V2-V1, V3-V1] is not zero. Therefore, conditions: 0 0, 0

Pseudo code implementation (principle is implemented in the DirectX PICK example): // triangular two side of the vector vector3 EDGE1 = V1 - V0; Vctor3 EDGE2 = V2 - V0; Vctor3 PVEC; VEC3CROSS (& PVEC, & DIR, & EDGE2); / / Differential float DET = VEC3DOT (& Edge1, & PVEC); // Dumotive // ​​DET Its Meaning is [-Dir, V2-V1, V3-V1] matrix expands Vector3 TVEC; IF (DET> 0) // {TVEC = ORIG - V0; // From the front cross-triangular, triangular and viewpoint faces on the front} else {tvec = V0 - orig; // Cross the triangle cross the triangle Det = -det;} IF (DET <0.0001F) / / Access to zero is considered to be 0 return false; / / find the value of U, the discharge of the linear equation group is equivalent to the spot exhibition * u = VEC3DOT (& tvec, & pVEC); if (* u <0.0f || * u> DET) Return false; // Require V. Vector3 QVEC; VEC3CROS (& QVEC, & TVEC, & EDGE1); * v = vec3dot (& Dir, & Dir, & qVEC); if (* v <0.0f || * u * v> DET) RETURN FALSE; / / Calculate T and confuse T, U, V as legitimate * T = D3DXVEC3DOT (& Edge2, & QVEC); // front T, V, u Take a coefficient Detfloat when calculating FINVDET = 1.0f / DET; * t * = finvdet; * u * = finvdet; * v * = finvdet; // Here this algorithm is given by Microsoft, from geometric perspective, it is very difficult to understand, the real method is According to the linear equation lease, it is convinced that the method in the text is in line with the linear equations, which is probably the principle of geometry and algebra.

Source (VC6.0 OpenGL Windows2000, Debug Pass): BOOL INTERSECTTRIANGLE () {GLFLOAT EDGE1 [3]; GLFLOAT EDGE2 [3];

EDGE1 [0] = V1 [0] -V0 [0]; EDGE1 [1] = V1 [1] -V0 [1]; EDGE1 [2] = V1 [2] -V0 [2];

EDGE2 [0] = V2 [0] -V0 [0]; EDGE2 [1] = V2 [1] -V0 [1]; EDGE2 [2] = V2 [2] -V0 [2];

GLFLOAT DIR [3]; DIR [0] = g_farxyz [0] -g_nearxyz [0]; DIR [1] = g_farxyz [1] -g_nearxyz [1]; DIR [2] = g_farxyz [2] -g_nearxyz [2] ;

GLFLOAT W = (GLFLOAT) SQRT (DOUBLE) POW (DIR [0], 2.0) (DOUBLE) POW (DIR [1], 2.0) (DOUBLE) POW (DIR [2], 2.0)); DIR [ 0] / = W; DIR [1] / = W; DIR [2] / = W; GLFLOAT PVEC [3]; PVEC [0] = DIR [1] * Edge2 [2] - DIR [2] * Edge2 [ 1]; PVEC [1] = DIR [2] * Edge2 [0] - DIR [0] * Edge2 [2]; PVEC [2] = DIR [0] * Edge2 [1] - DIR [1] * Edge2 [ 0];

GLFLOAT DET; DET = Edge1 [0] * PVEC [0] EDGE1 [1] * PVEC [1] Edge1 [2] * PVEC [2];

GLFLOAT TVEC [3]; IF (DET> 0) {TVEC [0] = g_nearxyz [0] - V0 [0]; TV [1] = g_nearxyz [1] - v0 [1]; TV [2] = g_nearxyz [ 2] - V0 [2];} else {TVEC [0] = V0 [0] - g_nearxyz [0]; TV [1] = v0 [1] - g_nearxyz [1]; tVEC [2] = v0 [2] - g_nearxyz [2]; DET = -det;} if (DET <0.0001F) Return False;

GLFLOAT U; U = TVEC [0] * PVEC [0] TVEC [1] * PVEC [1] TVEC [2] * PVEC [2]; if (u <0.0f || u> DET) Return False; GLFLOAT QVEC [3]; QVEC [0] = TVEC [1] * Edge1 [2] - TVEC [2] * Edge1 [1]; QVEC [1] = TVEC [2] * Edge1 [0] - TVEC [0] * Edge1 [2]; QVEC [2] = TVEC [0] * Edge1 [1] - TVEC [1] * Edge1 [0]; GLFLOAT V; V = DIR [0] * QVEC [0] DIR [1] * QVEC [1] DIR [2] * QVEC [2]; if (v <0.0f || U V> DET) Return False; GLFLOAT T = Edge2 [0] * QVEC [0] Edge2 [1] * QVEC [1] Edge2 [2] * QVEC [2]; GLFLOAT FINVDET = 1.0F / DET; t * = finvdet; u * = finvdet; v * = finvdet; return

}

Void Pick (GLFLOAT XPOS, GLFLOAT YPOS) {XPOS, YPOS; Glint Viewport [4]; GLDOUBLE MVMATRIX [16], Projmatrix [16]; Glint Realy; GLDOUBLE WX, WY, WZ;

Glgetintegerv (GL_ViewPort, viewport); Glgetdoublev (GL_MODELVIEW_MATRIX, MVMATRIX); GLGETDOUBLEV (GL_Projection_Matrix, Projmatrix);

Realy = viewport [3] - (GLINT) YPOS -1; // Left corner is coordinate original gluunproject (gldouble) XPOS, (GLDOUBLE) Realy, 0.0, MVMatrix, Projmatrix, ViewPort, & WX, & Wy, & WZ); g_nearxyz [ 0] = (GLFLOAT) WX; g_nearxyz [1] = (glfloat) WY; g_nearxyz [2] = (glfloat) WZ;

GluunProject (GLDOUBLE) XPOS, (GLDOUBLE) REAL, 1.0, MVMatrix, Projmatrix, ViewPort, & WX, & Wy, & WZ); g_farxyz [0] = (GLFLOAT) WX; g_farxyz [1] = (GLFLOAT) WY; G_FARXYZ [2 ] = (GLFLOAT) WZ;

g_color = 0.0; IF (intersectTriangle ()) g_color = 1.0;

} GLFLOAT V0 [3] = {1.0, 0.0, -1.0}; GLFLOAT V1 [3] = {0.0, 1.0, -1.0}; GLFLOAT V2 [3] = {0.0, 0.0, -2.0}; Void Drawglscene (GLVOID ) {glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin (GL_TRIANGLES); glColor3f (g_color, 0.0,1.0); glVertex3fv (V0); // if added glTranslatef transform function or the like, should radiation varies inversely glVertex3fv (V1); GlvertEX3FV (V2); glend (); swapbuffers (hdc);

}

This article ends. Email: lzhoumail@126.com

转载请注明原文地址:https://www.9cbs.com/read-86611.html

New Post(0)