你的位置:首页 > ASP.net教程

[ASP.net教程]SharpGL学习笔记(六) 裁剪变换


 

在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度方向上的裁剪. 任意角度的裁剪貌视是不可以的.

 

 本节源代码下载