在OpenGL中,除了視景體定義的6個裁剪平面(上下左右前後)外, 用戶還可以定義一個或者多個附加的裁剪平面,以去掉場景中無關的目標.
附加平面裁剪函數原型如下:
ClipPlane(OpenGL.GL_CLIP_PLANEi, double[] equation);
equation是一個擁有4個系數的數組, 它定義一個裁剪平面。equation參數指向平面方程Ax + By + Cz + D = 0的4個系數。
equation=(0,-1,0,0),前三個參數(0,-1,0)可以理解為法線向下,只有向下的,即Y<0的才能顯示,最後一個參數0表示從z=0平面開始。這樣就是裁剪掉上半平面。
相應的equation=(0,1,0,0)表示裁剪掉下半平面,
equation=(1,0,0,0)表示裁剪掉左半平面,
equation=(-1,0,0,0)表示裁剪掉右半平面,
equation=(0,0,-1,0)表示裁剪掉前半平面,
equation=(0,0,1,0)表示裁剪掉後半平面
上幾節,討論過透視投影和正射投影, 它們構成兩種視景體, 本身包含了裁剪功能, 這個附加的裁剪功能如下圖所示:

示意圖可能有些不太直觀, 筆者先引用3dsmax的裁剪效果, 讓大家對所謂的裁剪的效果有個主觀印象.
在3dsmax中, 攝像機有一個剪切平面的選項, 勾選後可以設定近距剪切的位置(左視圖那條傾斜的紅色線條就是近距剪切線的位置,它的位置是85.493), 設置一個值後, 看到如下圖所示的裁剪的效果.
如果你移動攝像機的位置, 那麼剪切的位置會隨之改變.

在OpenGL中, 經筆者測試, 發現視點變換並不會影響裁剪結果, 反而是模型的幾何變換(移動,旋轉,縮放) 影響裁剪結果.
我們以代碼來說明這個ClipPlane()函數的用法, 先上代碼:
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Windows.Forms;
9 using SharpGL;
10
11 namespace clipPlane
12 {
13
14 public partial class SharpGLForm : Form
15 {
16
17 public SharpGLForm()
18 {
19 InitializeComponent();
20 }
21
22 private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
23 {
24 OpenGL gl = openGLControl.OpenGL;
25 gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
26 gl.LoadIdentity();
27
28 double[] eqn = new double[4] { 1f, 0f, 0f, 0f };
29
30 gl.Color(1.0, 1.0, 1.0);
31
32 gl.PushMatrix();
33 {
34 gl.Translate(-2, -2, -3);
35 gl.Rotate(-90.0, 1.0, 0.0, 0.0);
36 drawSphere(gl);
37 }
38 gl.PopMatrix();
39
40 gl.PushMatrix();
41 {
42 //gl.ClipPlane(OpenGL.GL_CLIP_PLANE0, eqn);
43 //gl.Enable(OpenGL.GL_CLIP_PLANE0);
44 drawGrid(gl);
45 }
46 gl.PopMatrix();
47
48 gl.Flush();
49 }
50
51 private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
52 {
53 OpenGL gl = openGLControl.OpenGL;
54 gl.ClearColor(0, 0, 0, 0);
55 }
56
57 private void openGLControl_Resized(object sender, EventArgs e)
58 {
59
60 OpenGL gl = openGLControl.OpenGL;
61 gl.MatrixMode(OpenGL.GL_PROJECTION);
62 gl.LoadIdentity();
63 gl.Perspective(60.0f, (double)Width / (double)Height,1, 100.0);
64 gl.LookAt(0, 5, 10, 0, 0, 0, 0, 1, 0);
65 gl.MatrixMode(OpenGL.GL_MODELVIEW);
66 }
67
68 void drawSphere(OpenGL gl)
69 {
70 //畫二次曲面球體繪制過程
71 gl.PushMatrix();
72 gl.Translate(2f, 1f, 2f);
73
74 //繪制二次曲面
75 var sphere = gl.NewQuadric();
76 //設置二次卻面繪制風格。gluQuadricDrawStyle。一般都是選用GLU_FILL風格,采用多邊形來模擬
77 gl.QuadricDrawStyle(sphere, OpenGL.GLU_LINE);
78 //設置法線風格。gluQuadricNormals。一般都是使用GLU_SMOOTH風格,對每個頂點都計算法線向量,是默認方式
79 gl.QuadricNormals(sphere, OpenGL.GLU_SMOOTH);
80 //設置二次曲面的繪制方向。gluQuadricOrientation。一般使用GLU_OUTSIDE, 按照所有的法線都指向外面的方式繪制。是默認方式
81 gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE);
82 //設置紋理。gluQuadricTexture。設置是否自動計算紋理。默認是GLU_FALSE。當需要使用紋理時應修改為GLU_TRUE.
83 gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE);
84
85 gl.Sphere(sphere, 3f, 20, 10);
86 gl.DeleteQuadric(sphere);
87 gl.PopMatrix();
88 }
89
90 void drawGrid(OpenGL gl)
91 {
92 //繪制柵格線過程
93 gl.PushAttrib(OpenGL.GL_CURRENT_BIT); //保存當前屬性
94 gl.PushMatrix(); //壓入堆棧
95 gl.Translate(0f, 0f, 0f);
96 gl.Color(0f, 0f, 1f);
97
98 //在X,Z平面上繪制網格
99 for (float i = -50; i <= 50; i += 1)
100 {
101 //繪制線
102 gl.Begin(OpenGL.GL_LINES);
103 //X軸方向
104 gl.Vertex(-50f, 0f, i);
105 gl.Vertex(50f, 0f, i);
106 //Z軸方向
107 gl.Vertex(i, 0f, -50f);
108 gl.Vertex(i, 0f, 50f);
109 gl.End();
110 }
111 gl.PopMatrix();
112 gl.PopAttrib();
113 }
114
115
116
117 }
118 }
上面代碼中,我把42,43行有關裁剪的代碼注釋了, 這時運行的效果如下圖:
產生一個球體和一個柵格面, 我的裁剪會對這兩個對象都發生作用, 這樣便於觀察效果.

啟用第42,43行, 運行後, 裁剪發生作用, 效果是下面這樣的:
左半平面被去掉了. 因為裁剪會對場景中所有對象發生作用, 因此柵格面也被連累了.

如果你想移動裁剪面的位置, 你需要對球體做幾何變換. 改變下面這行代碼的參數就可以了.
gl.Translate(-2, -2, -3);
然而, 一般來說, 場景中的對象固定好位置之後, 是不能做幾何變換的. 如果即不做幾何變換, 又想裁剪該怎麼辦呢?
暫時我也不知道怎麼辦! 如果以後知道怎麼辦我會在這把這個知識點補全了. (如果你知道,謝謝回本貼教下我!)
下面是45度方向上的裁剪. 任意角度的裁剪貌視是不可以的.

本節源代碼下載