Original copyright of this article belongs to Baidu

**Laizhishen**All, if any reprinted, please explicitly mark the original author and original source as follows to show respect !!

**Author:****Laizhishen**

Original article: http://hi.baidu.com/laizhishen/blog/item/3d206d209cca9c54ac34de46.htmlFrustum pruning is a very important algorithm in clod. Many articles use a single sentence or directly provide code. However, mathematical derivation is rarely given. The purpose of this article is to explain the questions in the code. Perspective Projection is to transform the points in the camera space from the view frustum to the canonical view volume (CCV), that is, the view frustum of the world space) if any vertex in the projection matrix is transformed, it must be in the canonical view volume (CCV), that is, in (-1 )~ The value between (, 1) is 1. Here we define p0 = (-1,-) P1 = (1,-) P2 = (1) p3 = (-1,-) P4 = (-, 0) P5 = (, 0) P6 = (, 1) P7 = (-, 1) we build 6 faces through these 8 points, through 3 points of common surface, assuming the surface is pos0, pos1, pos2, u = Pos1-Pos0, V = Pos2-Pos0, then the normal vector n = u × V. Then d =-(n × pos0 ). Obtain the plane formula n and D of each plane to obtain a, B, c, d, (n of XN, YN, Zn, D, that is, a, B, c, d ). Attention should be paid to construct the order of points after the interview. d3d constructs the area clockwise. The normal is from the frustum to the outside. Near: (P0, P4, P5) n = (0, 0,-1), D = 0 0x + 0y-1z + 0 = 0 far: (P2, P6, P7) N = (, 1), D =-1 0x + 0y + 1z-1 = 0 left: (P0, P3, P7) n = (-, 0 ), D =-1-1x + 0y + 0z-1 = 0 right: (P1, P5, p6) n = (1, 0, 0 ), D =-1 1x + 0y + 0z-1 = 0 top: (P4, P7, p6) n = (0, 1, 0 ), D =-1 0x + 1y + 0z-1 = 0 bottom: (P0, P1, P2) n = (0,-1, 0 ), D =-1 0x-1y + 0z-1 = 0 assume that there is a point P '(x', y', C', 1) on a plane in these six planes ), the plane equation is a' x' + B 'y' + C' Z' + d' = 0. The coordinates before the projection transformation are p (x, y, z, 1), in the world space, the plane equation AX + by + cz + D = 0, if p 'Point in CVV, that point P (x, y, z, 1) must be in view frustum. Principle 1. from the introduction of inference, we can obtain the following equation | a' | A | (x', y', C', 1) × | B '| = 0 (x, y, z, 1) × | B | = 0 | C' | c | d' | d | simultaneously (x', y', C', 1) × tvproj = (X, Y, Z, 1) Note that tviewproj matrix = tview × tproj (that is, multiply the camera matrix and projection matrix. Is to convert the world coordinates to the change matrix of the video plane) combined with three equations, we can obtain | A | a' | tviewproj × | B | = | B '| equation 1 | c | C' | d | d' | through equation 1, we can find the plane equation AX + by + cz + D = 02 code void cfrustum: initfrustum1 (const d3dxmatrix & aoviewmatrix, const d3dxmatrix & aoprojmatrix) of six planes in the world coordinate system) {d3dxmatrix locombomatrix; d3dxmatrix loinvcombomatrix; d3dxmatrixmultiply (& locombomatrix, & aoviewmatrix, & aoprojmatrix); // obtain the inverse matrix of view * proj. d3dxmatrixinverse (& loinvcombomatrix, NUL L, & locombomatrix); // If the projection matrix is used, the points of all 3D world coordinates are changed to (-1 )~ Value Between (, 1. // fill in the critical value of the same space with mocvvpos. mocvvpos [0]. X =-1.0f; mocvvpos [0]. y =-1.0f; mocvvpos [0]. z = 0.0f; mocvvpos [1]. X = 1.0f; mocvvpos [1]. y =-1.0f; mocvvpos [1]. z = 0.0f; mocvvpos [2]. X = 1.0f; mocvvpos [2]. y =-1.0f; mocvvpos [2]. z = 1.0f; mocvvpos [3]. X =-1.0f; mocvvpos [3]. y =-1.0f; mocvvpos [3]. z = 1.0f; mocvvpos [4]. X =-1.0f; mocvvpos [4]. y = 1.0f; mocvvpos [4]. z = 0.0f; mocvvpos [5]. X = 1.0f; mocvvpos [5]. Y = 1.0f; mocvvpos [5]. z = 0.0f; mocvvpos [6]. X = 1.0f; mocvvpos [6]. y = 1.0f; mocvvpos [6]. z = 1.0f; mocvvpos [7]. X =-1.0f; mocvvpos [7]. y = 1.0f; mocvvpos [7]. z = 1.0f; // convert the CVV coordinates back to the world coordinates for (INT I = 0; I <8; I ++) d3dxvec3transformcoord (& mocvvpos [I], & mocvvpos [I], & loinvcombomatrix); // you can use the obtained world coordinates to create a plane of the flattened part. // The vector points to an external plane from the internal point of the intercept. d3dxplanefrompoints (& mofrustumplane [frustum_plane_front], mocvvpos, mocvvpos + 4, m Ocvvpos + 5); // near plane (near) d3dxplanefrompoints (& mofrustumplane [UNKNOWN], mocvvpos + 2, mocvvpos + 6, mocvvpos + 7); // far plane (FAR) d3dxplanefrompoints (& Symbol [Symbol], mocvvpos, mocvvpos + 3, mocvvpos + 7); // left plane (left) d3dxplanefrompoints (& mofrustumplane [Symbol], mocvvpos + 1, mocvvpos + 5, mocvvpos + 6); // right plane (right) d3dxplanefrompoints (& mofrustumplane [frustum_plane_top], Mo Cvvpos + 4, mocvvpos + 7, mocvvpos + 6); // top (top) d3dxplanefrompoints (& mofrustumplane [cursor], mocvvpos, mocvvpos + 1, mocvvpos + 2 ); // bottom plane (bottom)} the above Code is easy to understand and fully implemented according to the principle. However, every time we call this function, we require the inverse matrix of the tvproj matrix, at the same time, we also need to re-use points to construct each frustum plane and call the d3dxplanefrompoints function. Are there any better methods? Next we will optimize our code. before optimization, we will analyze Principle 2 1. in inference, we know that after P (x, y, z, 1) is transformed by the tviewproj matrix, we get the points p '(x', y', Z', W '), during the previous derivation, this point must be on a certain plane of frustum. at this time, we know that if every component of P is divided by W', We can normalize p' to the space of a cuboid, that is, x'/W ', y'/W' is in the [-] interval, and Z'/W' is in the [] interval. Therefore, if there is a point p1' after projection conversion, its x1 ', y1 'is in the [-W', W'] interval, and z1 is in the [0, W'] interval. This point must be in the cone. | A11, A12, A13, A14 | assume that tviewproj = [v0, V1, V2, V3] = | A21, A22, A23, A24 | A31, A32, A33, a34 | a41, a42, A43, and A44 | among them, V0, V1, V2, and V3 are four column vectors. p' = p × tviewproj = (P? V0, P? V1, P? V2, P? V3) = (x', y', Z', W') based on the range of X above, we have:-W' <= x' is-p '? V3 <= p '? V0 is p '? V0 + p '? V3 <= 0 get p '? (V0 + V3) <= 0 replace column vectors with matrix elements (X, Y, Z, 1 ). (m_11 + m_14, m12 + M24, M13 + m34, m14 + m44) <= 0 is (m_11 + m_14) * x + (m_12 + m_24) * Y + (m_13 + m_34) * z + (m_14 + m_44) * 1 <= 0. Simply put, This Is A ** x + B * Y + C * z + D * 1 <= 0, which describes a half space, it is the space on the right of the plane a * x + B * Y + C * z + D * 1 = 0. So we know that the Left cut surface of the cone is (m_11 + m_14) * x + (m_12 + m_24) * Y + (m_13 + m_34) * z + (m_14 + m_44) * 1 = 0. correspondingly, we can calculate the Left = (v0 + V3) of six cut surfaces ). right = (V3-V0) Bottom = (V3 + V1) Top = (V3-V1) near = (V2) far = (V3-V2) when the point is reduced, the formula AX + by + cz + DW can be used to check whether the point is large, 0, or small, and 0 to know whether it is inside or outside the plane. In actual calculation,, b, C, and D are normalized. Because when we process coordinates, almost all vertices are normalized. 2. code void cfrustum: initfrustum (const d3dxmatrix & aoviewmatrix, const d3dxmatrix & aoprojmatrix) {d3dxmatrix locombomatrix; trim (& locombomatrix, & aoviewmatrix, & aoprojmatrix ); // calculate the planes // neard3dxplane * lpplane = & mofrustumplane [frustum_plane_near]; lpplane-> A = locombomatrix. _ 14 + locombomatrix. _ 13; lpplane-> B = locombomatrix. _ 24 + locombomatrix. _ 23; lpplane-> C = locombomatrix. _ 34 + locombomatrix. _ 33; lpplane-> d = locombomatrix. _ 44 + locombomatrix. _ 43; d3dxplanenormalize (lpplane, lpplane); // farlpplane = & mofrustumplane [frustum_plane_far]; lpplane-> A = locombomatrix. _ 14-locombomatrix. _ 13; lpplane-> B = locombomatrix. _ 24-locombomatrix. _ 23; lpplane-> C = locombomatrix. _ 34-locombomatrix. _ 33; lpplane-> d = locombomatrix. _ 44-locombomatrix. _ 43; d3dxplanenormalize (lpplane, lpplane ); // Leftlpplane = & mofrustumplane [frustum_plane_left]; lpplane-> A = locombomatrix. _ 14 + locombomatrix. _ 11; // leftlpplane-> B = locombomatrix. _ 24 + locombomatrix. _ 21; lpplane-> C = locombomatrix. _ 34 + locombomatrix. _ 31; lpplane-> d = locombomatrix. _ 44 + locombomatrix. _ 41; d3dxplanenormalize (lpplane, lpplane); // rightlpplane = & mofrustumplane [frustum_plane_right]; lpplane-> A = locombomatrix. _ 14-locombomat Rix. _ 11; lpplane-> B = locombomatrix. _ 24-locombomatrix. _ 21; lpplane-> C = locombomatrix. _ 34-locombomatrix. _ 31; lpplane-> d = locombomatrix. _ 44-locombomatrix. _ 41; d3dxplanenormalize (lpplane, lpplane); // toplane ane = & mofrustumplane [frustum_plane_top]; lpplane-> A = locombomatrix. _ 14-locombomatrix. _ 12; lpplane-> B = locombomatrix. _ 24-locombomatrix. _ 22; lpplane-> C = locombomatrix. _ 34-locombomatrix. _ 32; lpplane-> d = locombomatrix. _ 44-locombomatrix. _ 42; d3dxplanenormalize (lpplane, lpplane); // bottomlpplane = & mofrustumplane [frustum_plane_bottom]; lpplane-> A = locombomatrix. _ 14 + locombomatrix. _ 12; // bottomlpplane-> B = locombomatrix. _ 24 + locombomatrix. _ 22; lplane-> C = locombomatrix. _ 34 + locombomatrix. _ 32; lpplane-> d = locombomatrix. _ 44 + locombomatrix. _ 42; d3dxplanenormalize (lpplane, lpplane);} 2nd Method in the not seen between, first saw the code http://www.racer.nl/reference/vfc_markmorley.htm, I think for a long time did not think clearly. Finally, I saw the explanation and despised my own mathematical logical reasoning. 3d seems that the difficulty lies in the way of thinking. For the same code processing, the second method is much faster. Judging that we already have the cropping body equation, when we need to crop a vertex, these six equations are enough. However, when we want to determine the visibility of a region, we perform some additional calculations. As shown in 2, the relationship between an object and a projection object can be roughly divided into four situations: surrounded, surrounded, intersection, and separation. The largest light blue rectangle in the figure contains the entire projection body. The small dark green rectangle is completely surrounded by the projection body. The light green rectangle and the projection body intersect. Objects can be seen in all three cases. The remaining red rectangle is separated from the projection body, and only it is completely unavailable. See figure 2. When processing node visibility, due to node irregularities. We also need to introduce the concept of the surrounding body. The so-called surround body is to use a relatively simple ry to measure another complex ry, so that it can just enclose another ry. The shape of the surrounded body is rectangular, square, and sphere. Sphere processing is the simplest, but the approximation is also the worst. We create an enclosure for each node. If we test this enclosure, we can determine the visibility of a node. Because the enclosure must be larger than this node, therefore, we can ensure that no visible node is cropped out of the projection body bool cfrustum: pointinfrustum (float afx, float afy, float afz) {// A * x + B * Y + C * z + D = 0 is in plane, for (INT I = 0; I <frustum_plane_count; I ++) {d3dxplane & loplane = mofrustumplane [I]; // reduce function call // If (TRIM (& mofrustumplane [I], & d3dxvector3 (afx, afy, afz) <0.0f) if (loplane. A * afx + loplane. B * afy + loplane. C * afz + loplane. d <0.0f) return false;} return true;} bool cfrustum: sphereinfrustum (float afx, float afy, float afz, float afradius) {// A * x + B * Y + C * z + D =-radius is in plane, for (INT I = 0; I <frustum_plane_count; I ++) {d3dxplane & loplane = mofrustumplane [I]; // reduce function calls by using formulas. // If (d3dxplanedotcoord (& mofrustumplane [I], & d3dxvector3 (afx, afy, afz) <-afradius) if (loplane. A * afx + loplane. B * afy + Loplane. C * afz + loplane. d <=-afradius) {return false ;}} return true;} bool cfrustum: cubeinfrustum (float afx, float afy, float afz, float aisize, bool & abiscompletelycontained) {float lfalfax = afx + aisize; float lfdeltax = afx-aisize; float lfalfay = afy + aisize; float lfdeltay = afy-aisize; float lfalfaz = afz + aisize; float lfdeltaz = afz-aisize; DWORD ldwnumpointinfrustum = 0; For (INT I = 0; I <frustum_plane_count; I ++) {Int J = 8; bool lbisinallplanes = true; d3dxplane & loplane = mofrustumplane [I]; // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfdeltax, lfdeltay, lfdeltaz) <0.0f) if (loplane. A * lfdeltax + loplane. B * lfdeltay + loplane. C * lfdeltaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfalfax, lfdeltay, lfdeltaz) <0.0f) If (loplane. A * lfalfax + loplane. B * lfdeltay + loplane. C * lfdeltaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfdeltax, lfalfay, lfdeltaz) <0.0f) if (loplane. A * lfdeltax + loplane. B * lfalfay + loplane. C * lfdeltaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfalfax, lfalfay, lfalfaz) <0.0f) if (loplane. A * lfalfax + loplane. B * lfalfay + loplane. C * lfdeltaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfdeltax, lfdeltay, lfalfaz) <0.0f) if (loplane. A * lfdeltax + loplane. B * lfdeltay + loplane. C * lfalfaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfalfax, lfdeltay, lfalfaz)) <0.0f) if (loplane. A * lfalfax + loplane. B * lfdeltay + loplane. C * lfalfaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfdeltax, lfdeltay, lfalfaz) <0.0f) if (loplane. A * lfdeltax + loplane. B * lfdeltay + loplane. C * lfalfaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If (d3dxplanedotcoord (& loplane [I], & d3dxvector3 (lfalfax, lfalfay, lfalf AZ) <0.0f) if (loplane. A * lfalfax + loplane. B * lfalfay + loplane. C * lfalfaz + loplane. d <0.0f) {lbisinallplanes = false; j --;} // If none contained, return false. if (0 = J) return false; // update counter if they were all in front of plane. if (lbisinallplanes) ++ ldwnumpointinfrustum;} abiscompletelycontained = (bool) (ldwnumpointinfrustum = frustum_plane_count); Return true;} all the above principles come to the network, some details are my own There is nothing special about sorting, mainly classification. In learning 3D, you must thoroughly understand the principles. In this way, when you accumulate a certain amount of time, you will find that 3D is not the case, but you must be diligent in reasoning with yourself.