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

     本节源代码下载

    原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/

  • 相关阅读:
    hdu 1171 Big Event in HDU (01背包)
    Codeforces 86C Genetic engineering (AC自己主动机+dp)
    ANDROID L——Material Design具体解释(动画篇)
    三层架构理论篇
    Linux下的tree命令 --Linux下文件夹树查看
    排序之冒泡排序、插入排序及希尔排序
    TRIZ系列-创新原理-9~11-预先反作用原理、预处理原理、预先防范原理
    Linux 获得机器的IP和网卡信息
    Hackerrank
    Android编程之Fragment使用动画造成Unknown animation name: objectAnimator异常
  • 原文地址:https://www.cnblogs.com/hackpig/p/5795915.html
Copyright © 2020-2023  润新知