Use OpenGL to obtain Ray objects

Source: Internet
Author: User

Use OpenGL to obtain Ray objects

There is already a complete theory about how to use the ray principle to pick up objects on the Internet, and DirectX also provides a pick example for demonstration. Here I will summarize these materials and theories a little, complete implementation under OpenGL is provided.
The relevant theories generally come from an English document and a summative Chinese document:
Http://www.gameres.com/Articles/Program/Visual/3D/pick_2004_529.htm
Http://www.mvps.org/directx/articles/rayproj.htm
The previous article describes the principle and implementation of using DirectX to pick up objects by Ray. The next article describes how to convert a two-dimensional screen space to a three-dimensional world space. The name of the previous article is "using the mouse to pick up elements in direct3d", which is very good and thorough. The next article describes the principles of Ray formation and provides source code examples.
The following is an implementation of OpenGL.

 

Step 1:
To convert screen coordinates to 3D World Space coordinates, OpenGL is much simpler than DirectX in this step. The gluunproject function can be used to directly obtain the corresponding 3D space coordinates of screen coordinates. The example is as follows:
Gluunproject (gldouble) x POs, (gldouble) ypos, 1.0, mvmatrix, projmatrix, viewport, & wx, & Wy, & WZ ); xpos and ypos are the screen coordinates of the origin at the lower left corner of the screen. 1.0 represents the world coordinates of zbuffer at 1.0 (the intersection of the distant cut plane). mvmatrix is the view matrix and getdoublev( gl_modelview_matrix, mvmatrix), projmatrix is the projection matrix, obtained through glgetdoublev( gl_projection_matrix, projmatrix), viewport is the viewport, obtained through glgetintegerv (gl_viewport, viewport, the remaining wx, Wy, and WZ are the coordinates of the world we want to get. The two coordinates are determined by the rays, or the origin point (viewpoint) can be used to replace one of the points, because this Ray is from the Viewpoint Departure.
Step 2:
The principle and formula used to calculate the intersection of rays and triangles to be detected are as follows.
Principle 1: any point in a triangle can be determined by the U, V, and the coordinates of the three vertices, where 0 <u <1 0 <v <1 ,, 0 <u + v <1, vpoint = V1 + u * (V2-V1) + V * (V3-V1), where V1, V2, V3 is the three vertices of the triangle, is the known amount.
Principle 2: any point on the Ray can be expressed by multiplying the direction vector (formatted) of the ray by its modulo (length of the vector), as follows: vpoint = originpoint + dir * Len
If the triangle and triangle intersect, the above two conditions must be met at the same time, so there are:

(-DIR) * Len + (V2-V1) * u + (V3-V1) * V = originpoint-V1

Equivalent equations: (Len, V, U is a variable, and others are constants)

(-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 equations, according to the gram law, [-Dir, V2-V1, V3-V1] is not zero.
So meet the conditions: 0 <v <u <1, Len> 0, 0 <u + v <1 and [-Dir, V2-V1, v3-V1: if it is not zero, the rays and triangles intersect.
(-Dir, V2-V1, V3-V1) written in the form of matrix:
|-Dir. X, v2.x-v1.x, v3.x-v1.x |
|-Dir. Y, v2.y-v1.y, v3.y-v1.x |
|-Dir. Z, v2.z-v1.z, v3.z-v1.z |

Pseudo code implementation (the principle is implemented by the source code in the DirectX pick example ):
// Vector of two sides of a triangle
Vector3 edge1 = V1-V0;
Vctor3 edge2 = v2-V0;
Vctor3 PVEC;
Vec3cross (& PVEC, & Dir, & edge2); // difference Product
Float det = vec3dot (& edge1, & PVEC); // Point product
// Det its meaning is [-Dir, V2-V1, V3-V1] matrix expansion
Vector3 tvec;
If (det> 0 )//
{
Tvec = orig-V0; // The triangle is crossed from the front, and the face relative to the triangle and viewpoint is the front.
}
Else
{
Tvec = V0-orig; // opposite side crossing triangle
Det =-Det;
}

If (det <0.0001f) // 0 if it is near zero
Return false;

// Calculate the value of U. After the solution of the linear equations is expanded, it is equivalent to the Point product expansion.
* U = vec3dot (& tvec, & PVEC );
If (* u <0.0f | * u> DET)
Return false;

// Evaluate the value of V
Vector3 qvec;
Vec3cross (& qvec, & tvec, & edge1 );
* V = vec3dot (& Dir, & qvec );
If (* v <0.0f | * u + * V> DET)
Return false;

// Calculate T, and scale T, U, and V to a valid value.
* T = d3dxvec3dot (& edge2, & qvec );
// The preceding T, V, and u multiply by one coefficient in calculation.

Float finvdet = 1.0f/det;
* T * = finvdet;
* U * = finvdet;
* V * = finvdet;
// This algorithm is provided by Microsoft. It is hard to understand its meaning from a geometric perspective. The real method is to lease and solve the problem based on linear equations, coincidentally, the methods in this article are exactly the same as those in the linear equations. This is probably the principle that ry is connected to algebra.

Source code (vc6.0 + OpenGL + Windows2000, debugging successful ):
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];
Tvec [1] = g_nearxyz [1]-V0 [1];
Tvec [2] = g_nearxyz [2]-V0 [2];

}
Else
{

Tvec [0] = V0 [0]-g_nearxyz [0];
Tvec [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 true;

}

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; // The coordinate origin in the lower left corner
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) realy, 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 a transformation function such as gltranslatef is added, the ray changes in reverse order.
Glvertex3fv (V1 );
Glvertex3fv (V2 );
Glend ();
Swapbuffers (HDC );
}

}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.