Nehe OpenGL tutorial (28th)

Source: Internet
Author: User
Tags mathematical functions

Lesson 1

Besell surface:

This is a course about mathematical operations, and there is nothing else. Come on, look at it with confidence.

Besell Surface

By David nikdel (ogapo@ithink.net)

This tutorial is intended to introduce the surface of besell. I hope someone who knows more about art can use her to make some cool stuff and show it to everyone. In this tutorial, you cannot create a complete shell database. Instead, you can use a program to demonstrate concepts to familiarize yourself with how the surface is implemented. This is not a formal article. To facilitate understanding, I may not have a proper terminology in some places. I hope everyone can adapt to this article. Finally, it's a shame to be familiar with the surface of besell and want to see how I write it.-) But if you find any flaws to let me or nehe know, after all, what if no one is perfect? Also, all the code is not optimized as I usually write a program, which is intentional. I think everyone can understand what it is. Well, I want to introduce it here. Continue to read the following!

Mathematics: The Sound Of The Devil: (warning: the content is a bit long ~)

Well, if you want to understand the surface of besell, it is difficult to understand its basic mathematical knowledge. If you do not want to read this part or you already know her mathematical knowledge, you can skip it. First, I will describe the besell curve and then introduce the generation of the besell surface.
The strange thing is that if you have used a graphics program, you are already familiar with the besell curve. Maybe you are using another name. They are the most basic method to draw a curve, and are usually expressed as a series of points. Two points and two points represent the tangent of the left and right sides. Shows an example.

 

This is the most basic besell curve (long points are made up of many points (not found )). This curve is defined by four points and has two endpoints and two intermediate control points. These points are the same for the computer, but we usually connect the first and second vertices separately, because their connections are tangent to the short point. A curve is a parameterized curve. When you draw a curve, you can find several connections on average. In this way, you can control the accuracy (and calculation amount) of curve and surface ). The most common method is to make a small subdivision at a long distance and multiple subdivisions at a short distance. For the point of view, it seems that the surface is always intact, and the influence on the speed is always minimal.
The besell surface is based on a basic equation, and other complicated aspects are based on this. The equation is:

T + (1-T) = 1

It looks simple, isn't it? Indeed, this is the most basic besell curve, a one-dimensional curve. You may have guessed from the terminology that the Bessel curve is in the polynomial form. From linear algebra, a one-dimensional polynomial is a straight line. Well, because the basic equation is true for all T, we can square or cube on both sides. How can this problem be solved? The equation is true, right? Okay. Let's try cube.

(T + (1-T) ^ 3 = 1 ^ 3

T ^ 3 + 3 * t ^ 2 * (1-T) + 3 * T * (1-T) ^ 2 + (1-T) ^ 3 = 1

This is the most commonly used equation for us to calculate the besell surface. A) She is the least-dimensional polynomial that does not need to be in a plane (with four control points), and B) the tangent lines on both sides are not correlated (for two dimensions, there are only three control points ). So have you seen the besell curve? We don't even have one, because I need to add something.
Well, because the left side of the equation is equal to 1, it is certain that if you add all the items together, it is still equal to 1. Does this mean that the number of each control point can be determined by calculating the point above the curve? (The answer is yes.) You are right! When we want to calculate the value at a point on the curve, we only need to use the control point (expressed as a vector) multiplied by each part to add it. Basically, we need to use 0 <= T <= 1, but it is not necessary. I don't understand? Here are functions:

P1 * t ^ 3 + p2 * 3 * t ^ 2 * (1-T) + P3 * 3 * T * (1-T) ^ 2 + P4 * (1-T) ^ 3 = pnew

Since polynomials are continuous, there is a good way to interpolation between four points. The curve passes through only P1 and P4, respectively when T =.
Okay, everything is fine, but now how can I use this in 3D? In fact, it is very simple. To create a besell surface, you need 16 control points (4*4) and 2 variables T and V. What you need to do is calculate the points of the four parallel curves in the component V, and then calculate the points in the component t using these four points. After calculating enough of these points, we can connect them with a triangle to draw the besell surface.

Well, I think there is enough background in mathematics. Check the code!

# Include <math. h> // mathematical Library
# Include <stdio. h> // standard input/output Library
# Include <stdlib. h> // standard library

Typedef struct point_3d {// structure of 3D points
Double X, Y, Z;
} Point_3d;

Typedef struct bpatch {// Bessert patch Structure
Point_3d anchors [4] [4]; // consists of 4x4 Grids
Gluint dlbpatch; // The Name Of The display list of the Paster.
Gluint texture; // the texture of the patch.
} Bezier_patch;

Bezier_patch mybezr; // create a surface structure
Bool showcpoints = true; // whether the control point is displayed
Int divs = 7; // The subdivision precision controls the display precision of the surface.


Below are some simple vector mathematical functions. If you are a C ++ enthusiast, you can use a vertex class (which must be 3d ).

// Add two vectors, P = p + q
Point_3d pointadd (point_3d P, point_3d q ){
P. x + = Q. X; p. Y + = Q. Y; p. Z + = Q. Z;
Return P;
}

// Multiply vector and scalar P = C * P
Point_3d pointtimes (double C, point_3d p ){
P. x * = C; p. y * = C; p. z * = C;
Return P;
}

// Create a 3D vector
Point_3d makepoint (double A, double B, double C ){
Point_3d P;
P. x = A; p. Y = B; p. z = C;
Return P;
}


This is basically a three-dimensional function written in C. She uses the U variable and the array of four vertices to calculate the curve points. Each time we add a certain value to U, from 0 to 1, we can get a good approximate curve.
The estimator defines the Curve Based on the Bernstein Polynomial and defines P (U'):
P (U') = Σ BNI (U') RI

Here, Ri is the control point.
BNI (U') = [Ni] u' I (1-u') n-I

And 00 = 1, [N0] = 1

U' = (u-u1)/(u2-u1)

The control point is 4 when it is a bésel curve, and the corresponding four Bernstein polynomials are:
1. B30 = (1-u) 3
2. b31 = 3u (1-u) 2
3. B32 = 3u2 (1-u)
4. B33 = U3


// Calculate the value of the besell Equation
// The U range of the variable is between 0 and 1.
Point_3d Bernstein (float U, point_3d * P ){
Point_3d A, B, C, D, R;

A = pointtimes (POW (u, 3), P [0]);
B = pointtimes (3 * POW (u, 2) * (1-u), P [1]);
C = pointtimes (3 * u * POW (1-u), 2), P [2]);
D = pointtimes (POW (1-u), 3), P [3]);

R = pointadd (a, B), pointadd (c, d ));

Return R;
}


This function completes sharing, generates all triangles, and stores them in the display list. In this way, we do not need to re-calculate the surface every time, except when it changes. In addition, you may want to use a cool effect and use the Morphing tutorial to change the position of the control point. This can be a smooth, organic, and morphing effect, with only a little overhead (you only need to change 16 points, but you need to calculate again ). The "last" array element is used to save the previous vertex (because the triangle belt requires two rows ). Furthermore, texture coordinates are calculated by the U and V representing the percentage (flat ing ).
Another thing we didn't do is to compute the normal vector for illumination. In this step, you have two options. The first is to find the center of each triangle and calculate the tangent of X and Y axes. Then, the cross product is used to obtain the vertical and two vector vectors, and then normalize them to obtain the normal vector. Or (well, this is a better way) You can get an approximate value using the triangle's normal vector (Calculated using your favorite method. I like the latter; I don't think it's worth a little attention to speed.

// Generate the display list of the besell Surface
Gluint genbezr (bezier_patch patch, int divs ){
Int u = 0, V;
Float py, PX, pyold;
Gluint drawlist = glgenlists (1); // create a display list
Point_3d temp [4];
Point_3d * Last = (point_3d *) malloc (sizeof (point_3d) * (divs + 1); // assign the corresponding memory for each curve with a finer score

If (patch. dlbpatch! = NULL) // delete a display list if it exists
Gldeletelists (patch. dlbpatch, 1 );

Temp [0] = patch. Anchors [0] [3]; // obtain four control points in the U direction
Temp [1] = patch. Anchors [1] [3];
Temp [2] = patch. Anchors [2] [3];
Temp [3] = patch. Anchors [3] [3];

For (V = 0; v <= divs; V ++) {// create the parameter of each split point based on the detailed score
Px = (float) V)/(float) divs );
// Use the coordinates of the Split points obtained by the Bernstein Function
Last [v] = Bernstein (PX, temp );
}

Glnewlist (drawlist, gl_compile); // create a new display list
Glbindtexture (gl_texture_2d, patch. Texture); // specify the texture.

For (u = 1; U <= divs; U ++ ){
Py = (float) U)/(float) divs); // calculate the parameter of the subdivision point in the V direction.
Pyold = (float) u-1.0f)/(float) divs); // the parameter of the subdivision point in the previous v direction

Temp [0] = Bernstein (PY, patch. Anchors [0]); // calculates the control point of the besell surface at each subdivision point v.
Temp [1] = Bernstein (PY, patch. Anchors [1]);
Temp [2] = Bernstein (PY, patch. Anchors [2]);
Temp [3] = Bernstein (PY, patch. Anchors [3]);

Glbegin (gl_triangle_strip); // start to draw the triangle band

For (V = 0; v <= divs; V ++ ){
Px = (float) V)/(float) divs); // draw sequentially along the U axis

Gltexcoord2f (pyold, PX); // you can specify the texture coordinates.
Glvertex3d (last [v]. X, last [v]. Y, last [v]. z); // draw a vertex

Last [v] = Bernstein (PX, temp); // create the next Vertex
Gltexcoord2f (PY, PX); // you can specify a texture.
Glvertex3d (last [v]. X, last [v]. Y, last [v]. z); // draw a new vertex
}

Glend (); // draw the ending triangle band
}

Glendlist (); // display the end of list painting

Free (last); // release the allocated memory
Return drawlist; // return the created display list.
}


Here we call a matrix that I think has some cool values.

Void initbeier (void ){
Mybesuppliers. Anchors [0] [0] = makepoint (-0.75,-0.75,-0.50); // set the control point of the besell Surface
Mybezr. Anchors [0] [1] = makepoint (-0.25,-0.75, 0.00 );
Mybezr. Anchors [0] [2] = makepoint (0.25,-0.75, 0.00 );
Mybezr. Anchors [0] [3] = makepoint (0.75,-0.75,-0.50 );
Mybesuppliers. Anchors [1] [0] = makepoint (-0.75,-0.25,-0.75 );
Mybezr. Anchors [1] [1] = makepoint (-0.25,-0.25, 0.50 );
Mybezr. Anchors [1] [2] = makepoint (0.25,-0.25, 0.50 );
Mybezr. Anchors [1] [3] = makepoint (0.75,-0.25,-0.75 );
Mybezr. Anchors [2] [0] = makepoint (-0.75, 0.25, 0.00 );
Mybezr. Anchors [2] [1] = makepoint (-0.25, 0.25,-0.50 );
Mybezr. Anchors [2] [2] = makepoint (0.25, 0.25,-0.50 );
Mybezr. Anchors [2] [3] = makepoint (0.75, 0.25, 0.00 );
Mybezr. Anchors [3] [0] = makepoint (-0.75, 0.75,-0.50 );
Mybezr. Anchors [3] [1] = makepoint (-0.25, 0.75,-1.00 );
Mybezr. Anchors [3] [2] = makepoint (0.25, 0.75,-1.00 );
Mybezr. Anchors [3] [3] = makepoint (0.75, 0.75,-0.50 );
Mybezr. dlbpatch = NULL; // The default display list is 0.
}


This is an optimized bitmap function. You can easily put them into a simple loop to call a group.

// Load a *. BMP file and convert it to a texture

Bool loadgltexture (gluint * texpntr, char * name)
{
Bool success = false;
Aux_rgbimagerec * textureimage = NULL;

Glgentextures (1, texpntr); // generate texture 1

File * test = NULL;
Textureimage = NULL;

Test = fopen (name, "R ");
If (test! = NULL ){
Fclose (test );
Textureimage = auxdibimageload (name );
}

If (textureimage! = NULL ){
Success = true;

// Bunding texture
Glbindtexture (gl_texture_2d, * texpntr );
Glteximage2d (gl_texture_2d, 0, 3, textureimage-> sizex, textureimage-> sizey, 0, gl_rgb, gl_unsigned_byte, textureimage-> data );
Gltexparameteri (gl_texture_2d, gl_texture_min_filter, gl_linear );
Gltexparameteri (gl_texture_2d, gl_texture_mag_filter, gl_linear );
}

If (textureimage-> data)
Free (textureimage-> data );

Return success;
}


Only the surface is initialized here. This is used every time you create a surface. Again, this is a good place to use C ++ (besell Curved Surface class ?).

Int initgl (glvoid) // initialize OpenGL
{
Glable (gl_texture_2d); // uses a 2D Texture
Glshademodel (gl_smooth); // Use smooth coloring
Glclearcolor (0.05f, 0.05f, 0.05f, 0.5f); // sets the black background.
Glcleardepth (1.0f); // sets the depth cache.
Glable (gl_depth_test); // use the deep Cache
Gldepthfunc (gl_lequal); // sets the depth equation.
Glhint (gl_perspective_correction_hint, gl_nicest );

Initbezr (); // initialize the besell Surface
Loadgltexture (& (mybezy. Texture), "./data/nehe.bmp"); // load texture
Mybesuppliers. dlbpatch = genbesuppliers (mybesuppliers, Divs); // create a display list

Return true; // initialization successful
}


First, call the besell display list. Draw a line connecting the control point (if the edges are to be painted. You can use the space key to switch this.

Int drawglscene (glvoid) {// draw a scenario
Int I, J;
Glclear (gl_color_buffer_bit | gl_depth_buffer_bit );
Glloadidentity ();
Gltranslatef (0.0f, 0.0f,-4.0f); // four units move into the screen
Glrotatef (-75.0f, 1.0f, 0.0f, 0.0f );
Glrotatef (Rotz, 0.0f, 0.0f, 1.0f); // rotate an angle

Glcalllist (mybezr. dlbpatch); // call the display list to draw the besell surface.

If (showcpoints) {// whether to draw a Control Point
Gldisable (gl_texture_2d );
Glcolor3f (1.0f, 0.0f, 0.0f );
For (I = 0; I <4; I ++) {// draw a horizontal line
Glbegin (gl_line_strip );
For (j = 0; j <4; j ++)
Glvertex3d (mybezr. Anchors [I] [J]. X, mybezr. Anchors [I] [J]. Y, mybezr. Anchors [I] [J]. z );
Glend ();
}
For (I = 0; I <4; I ++) {// draw a vertical line
Glbegin (gl_line_strip );
For (j = 0; j <4; j ++)
Glvertex3d (mybeener. Anchors [J] [I]. X, mybeener. Anchors [J] [I]. Y, mybezr. Anchors [J] [I]. z );
Glend ();
}
Glcolor3f (1.0f, 1.0f, 1.0f );
Glable (gl_texture_2d );
}

Return true; // success
}


The killglwindow () function has not been changed.

The createglwindow () function has not been changed.

I added the code for rotating the surface here to increase/decrease the resolution, and display or not the control point connections.

If (Keys [vk_left]) Rotz-= 0.8f; // left click to rotate to the left
If (Keys [vk_right]) Rotz + = 0.8f; // right-click and rotate to the right
If (Keys [vk_up]) {// press the upper key to increase the number of surface segments
Divs ++;
Mybesuppliers. dlbpatch = genbesuppliers (mybesuppliers, Divs); // update the display list of the besell surface.
Keys [vk_up] = false;
}
If (Keys [vk_down] & divs> 1) {// press the key to reduce the number of surface subdivisions
Divs --;
Mybesuppliers. dlbpatch = genbesuppliers (mybesuppliers, Divs); // update the display list of the besell surface.
Keys [vk_down] = false;
}
If (Keys [vk_space]) {// switch the visibility of the control point by Space
Showcpoints =! Showcpoints;
Keys [vk_space] = false;
}


Well, I hope this tutorial will make you feel at ease, and you now like me to enjoy the besell surface .; -) If you like this tutorial, I will continue to write an article about the NLE.
 

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.