SummaryThis article briefly describes how to read and display models in the 3DS file in OpenGL, and focuses on the mathematical basics and programming methods for freely rotating models by dragging the mouse.
KeywordsOpenGL 3DS file format VC ++ free rotation
Many papers and books have mentioned how to read and display models in 3DS files in OpenGL. But in many cases, it is not enough to read and display only. We need to observe the model from various angles in order to better understand the model form and form a more intuitive perceptual knowledge. For example, in the diagnosis of a fracture on the top of the humerus, if a three-dimensional model is used to simulate the rotation of the broken bone dislocation after the fracture, you can only drag the mouse to view the fracture from any angle, which will be of great benefit to the doctor for correct diagnosis. This is why we considered the original intention of implementing this feature. This article will briefly introduce the 3DS file format, how to read and display the model, and focus on the mathematical basics and programming methods and experience of freely rotating the model by dragging the mouse.
3DS file format and some experience in reading and displaying models in files.
A 3DS file is composed of multiple chunks ). So far, there has not been an official document describing its format, so there are still many unknown blocks. However, this does not affect the model we read into the 3DS file. This is because when we read data, we can selectively read the required blocks according to our own needs, and ignore those uninterested or unknown blocks. This is the benefit of the block structure.
A block consists of block information and block data. The block information is composed of the block ID (two-byte long identifier, such as 4d4d) and the block length (four bytes, which is actually the number of offset bytes of the next block. You can use VC ++ to open a 3DS file in hexadecimal notation and you can clearly see its structure. When reading a file with this block structure (a large block is nested with small blocks, and the block structure is fixed), it can be fully implemented using recursive methods and returned to the upper level (after reading the sub-block, returns the parent block.) The condition is whether the number of bytes of the currently read block is equal to the length of the block. Switch from parent block to sub-block reading. You can use the switch statement to determine which branch to enter by the sub-block ID.
Because there are many ready-made programs on the Internet, it is enough to find a program with better class encapsulation and transplant it to your own project. Of course, you need to make some small changes, such as modifying the display and Control Parts Based on your own needs.
Mathematical basis for freely rotating models
We use the mouse to rotate the model, just like holding a virtual ball containing the model. By clicking the mouse, a point is determined on the virtual ball, and dragging the mouse is to move the point. In this way, the virtual ball is rotated and the model is rotated at the same time.
The center of the virtual ball is in the center of the display, so that half of the ball is outside the display (outer hemisphere, 1 ). The point we click with the mouse is defined as the point on the outer hemisphere. The mathematical definition of this ing relationship is as follows:
(X, Y) is the screen coordinate of the center of the ball, and r is the radius of the ball.
The next step is to determine how to determine the rotation axis and angle after two points (starting point and ending point) are given on the ball. As shown in figure 2, the rotation axis is the normal vector of the plane formed by the two mouse vectors (m1 and m2). Therefore, we can obtain the cross multiplication of M1 and M2, namely:
The rotation angle is the angle A between M1 and M2. Therefore:
A = ACOs (m1 * m2) (Type 3) |
In practice, we prefer to take twice the value of a for rotation. This will rotate the model more effectively. If you click the middle left edge of the view and drag it to the middle right edge of the view, you can rotate the model 360 degrees with the Y axis as the axis of rotation.
As shown in figure 3, during the rotation process, the rotating arc formed by the synthesis of two arcs (R1 and R2) is equal to the starting point of R1 and the ending point of R2. That means the rotation of the virtual ball we define is only determined by the start point and the end point.
Programming methods and experiences for free rotation
1. First, create a virtual ball
Using an object-oriented method to solve the problem can make the solution portable and maintainable. VC ++ is a powerful object-oriented programming tool. Therefore, we use the VC ++ Object-Oriented Programming solution to implement the free rotation function. The virtual ball is declared as follows:
Class virtualball { Protected: Void _ maptosphere (const point2ft * newpt, vector3ft * newvec) const; Public: // constructor and destructor Virtualball (glfloat newwidth, glfloat newheight ); ~ Virtualball () {/* do not do anything */}; // Set the border. When the window size changes, make the virtual ball adapt to the window size. Void setbounds (glfloat newwidth, glfloat newheight) Void click (const point2ft * newpt); // press the mouse to map the start point to the virtual ball // Drag the mouse. The second mouse coordinate is updated here and mapped to the virtual ball to calculate the rotation. // Information of the vector and angle of the axis, and save them to a ry newrot (the first three elements are // Coordinate information. The last element is the angle information, which is actually the point multiplication of two vectors) Void drag (const point2ft * newpt, quat4ft * newrot ); Protected: Vector3ft stvec; // Save the vector (starting point) when the mouse clicks) Vector3ft envec; // Save the vector (endpoint) when dragging) Glfloat adjustwidth; // use the setbounds function to adjust the window. Glfloat adjustheight; } |
2. Map the mouse coordinates to the coordinates on the virtual ball.
To achieve the purpose of rotating the model through virtual ball rotation, the key is to map the coordinates of Mouse clicking and dragging in the view to the coordinates on the virtual ball.
For this reason, we should first move the mouse over and drag the range [0 ~ Width), [0 ~ Height) ing to [-1 ~ 1], [1 ~ -1] (In ing, the Y coordinate symbol is reversed, otherwise the correct result is not obtained in OpenGL ). In this way, mathematical computation can be simpler, and its ing is as follows:
Mousept. x = (mousept. X/(width-1)/2)-1 ); Mousept. Y =-(mousept. Y/(height-1)/2)-1 ); |
Second, calculate the mouse vector and map the mouse coordinates to the virtual ball. This step can be completed according to the definition of expression 1.
3. Related variable settings
To achieve rotation, we also need some variables:
Matrix4ft transform // final transformation, 4*4 matrix, initialized as the unit matrix Matrix3ft lastrot // The last rotation, 3*3 matrix, required because the rotation result is to be superimposed. Matrix3ft thisrot // This rotation, 3x3 matrix. Point2ft mousept; // The current mouse Coordinate Bool isclicked = false; // The identifier of the mouse. Bool isrclicked = false; // The identifier of the right-click operation. Bool isdragging = false; // The identifier of the mouse drag. |
Here, transform is our final transformation result, lastrot is the rotation result obtained by the last mouse drag, and thisrot is the result of the current mouse drag. They are all initialized as a matrix of units.
When we click the mouse, we start to rotate from the rotation matrix. When dragging the mouse, we calculate the rotation from the initial point to the drag point. Although we use this information to rotate the model on the screen, it is worth noting that we are not actually rotating the virtual ball itself. Therefore, to obtain the cumulative rotation result, we must find our own solution, which is the reason for the introduction of lastrot. If no rotation is accumulated, the model will suddenly return to the original state when we click the mouse icon. For example, if you want to get a result of 135 degrees after 90 degrees of rotation on the X axis and then 45 degrees, but what you actually get is 45 degrees. The next time you click the mouse, it will return to the original 0-degree state.
For other variables, We need to update them at the appropriate time and place. The virtual ball needs to reset its boundary when the window size is changed; mousept is updated when the mouse is clicked and dragged; isclicked and isrclicked respectively indicate whether the left and right mouse buttons are pressed, isclicked is used to determine whether it is in the press and drag state. We use isrclicked to reset all the rotations and bring them back to the matrix state.
4. Update the rotation matrix
With the above variable updates, the next step is to update the rotation matrix based on these updates:
Void crenderview: ontimer (uint nidevent) { If (m_completed) { M_completed = false; If (isrclicked) // If you right click, reset the Rotation { Matrix3fsetidentity (& lastrot); // reset lastrot to the unit matrix Matrix3fsetidentity (& thisrot); // reset thisrot to the unit matrix Matrix4fsetrotationfrommatrix3f (& transform, & thisrot );} If (! Isdragging) // No drag { If (isclicked) // click it for the first time { Isdragging = true; // preparations for dragging Lastrot = thisrot; Virtualball. Click (& mousept ); } } // Update the start point to prepare for dragging Else { If (isclicked) // The mouse is still pressed, indicating that the mouse is still dragging { Quat4ft thisquat; // a quaternary element used to store rotation information Arcball. Drag (& mousept, & thisquat ); // Convert the Quaternary element into a rotating Matrix Matrix3fsetrotationfromquat4f (& thisrot, & thisquat ); Matrix3fmulmatrix3f (& thisrot, & lastrot); // cumulative rotation result // Get our final rotation result Matrix4fsetrotationfrommatrix3f (& transform, & thisrot ); } Else // undragged Isdragging = false; } M_opengldisplay.displayscene (m_p3dmodel );// M_completed = true; } Cview: ontimer (nidevent ); } |
The function for converting the Quaternary element into a rotation matrix is:
Static void matrix3fsetrotationfromquat4f (matrix3ft * newobj, const quat4ft * Q1) { Glfloat N, S; Glfloat XS, ys, ZS; Glfloat wx, Wy, WZ; Glfloat XX, XY, xz; Glfloat YY, YZ, ZZ; Assert (newobj & Q1 ); N = (Q1-> S. x * Q1-> S. x) + (Q1-> S. y * Q1-> S. y) + (Q1-> S. z * Q1-> S. z) + (Q1-> S. W * Q1-> S. W ); S = (n> 0.0f )? (2.0f/N): 0.0f; Xs = Q1-> S. x * s; ys = Q1-> S. y * s; Zs = Q1-> S. z * s; Wx = Q1-> S. W * Xs; WY = Q1-> S. W * ys; WZ = Q1-> S. W * Zs; Xx = Q1-> S. x * Xs; xy = Q1-> S. x * ys; xz = Q1-> S. x * Zs; YY = Q1-> S. y * ys; YZ = Q1-> S. y * Zs; ZZ = Q1-> S. z * Zs; Newobj-> S. xx = 1.0f-(yy + zz ); Newobj-> S. YX = xy-WZ; Newobj-> S. zx = xz + WY; Newobj-> S. XY = xy + WZ; Newobj-> S. yy = 1.0f-(xx + zz ); Newobj-> S. ZY = YZ-wx; Newobj-> S. xz = xz-Wy; Newobj-> S. YZ = yz + wx; Newobj-> S. ZZ = 1.0f-(xx + YY ); } |
Finally, apply the transformation result to the model read from the 3DS file:
Glpushmatrix (); Glmultmatrixf (transform. m); // apply the rotating matrix to the model. Glbegin (drawingmode ); ......... // This is the place where the model is to be drawn, that is, the place where the model is located. Glend (); Glpopmatrix (); |
Analysis of rotation results and Problems
Free rotation effect 4 is shown. This method of rotating the model in the 3DS file with a virtual ball is simple, convenient, and practical to achieve the expected purpose. However, this method is worth improving. The center of the virtual ball is relatively fixed (always in the center of the window). If the center of the model is too far away from the center of the virtual ball, the rotation effect is not very good. The simplest solution is to move the center of the model to the coordinate origin before using 3DS MAX to export the 3DS file. This is a temporary solution, but it is applicable and simple. However, it is troublesome to solve the problem. The center of the computing model can be used to determine the center of the virtual ball, so that the two centers overlap. If there are multiple models, you should also consider implementing the Mouse capture model function, adjust the center of the virtual ball according to the selected model.
Conclusion
This article focuses on the mathematical basis and programming process for realizing the free rotation of models in the 3DS file. This work is an important part of the computer-aided diagnosis of an on-board fracture program. It helps doctors observe Fracture Simulation from various angles and form a more intuitive perceptual knowledge. This method can be used for models in other file formats or models in the auxiliary library to achieve free rotation, so it has a strong portability and applicable value.