计算机图形学学习笔记(6.1):直线段裁剪
屏幕映射的概念
如下图所示,要将实体显示在2D的屏幕上,需要先将实体在规范化的观察空间中进行投影变换,然后进行裁剪。这个过程就叫屏幕映射。

裁剪要处理的问题,就是将在观察窗口内部的图形裁剪出来,进行显示。在观察窗口之外的图形,将不被显示。如下图:

首先需要解决的是直线段裁剪问题。下面介绍两个非常著名的算法。
直线段裁剪
Cohen-Sutherland方法
要解决的问题: 对直线段P1 (x1 ,y1 ) -P2 (x2 ,y2)进行裁剪。
Cohen-Sutherland方法:基于编码的裁剪方法
基本思想:对每条直线段P1 (x1 ,y1 )P2 (x2 ,y2)分三种情况处理
(1) 直线段完全可见,“简取”之。
(2) 直线段完全丌可见,“简弃”之。
(3) 直线段既不满足“简取”的条件,也不满足“简弃”的条件,需要对直线段按交点进行分段,分段后重复上述处理。



编码:对于任一端点(x,y),根据其坐标所在的区域,赋予一个4位的二进制码D3D2D1D0。
编码规则如下:
-
若x<wxl,则D0=1,否则D0=0;
-
若x>wxr,则D1=1,否则D1=0;
-
若y<wyb,则D2=1,否则D2=0;
-
若y>wyt,则D3=1,否则D3=0.
如下图:

裁剪一条线段时,先求出端点p1和p2的编码 code1和code2,然后:
(1)若code1|code2=0,对直线段应简取之。
(2)若code1&code2≠0,对直线段可简弃之。
(3)若上述两条件均丌成立。则需求出直线段不窗口边界的交点。在交点处把线段一分为二, 其中必有一段完全在窗口外,可以弃之。再对另一段重复进行上述处理,直到该线段完全被舍弃或者找到位于窗口内的一段线段为止。
情况(3)具体做法:按左、下、右、上的顺序求出直线段与窗口边界的交点,分段处理。下图是一个例子:

对于情况(3),还有另一种方法:二分法。即当对直线段不能简取也不能简弃时,简单地把线段等分为二段,对两段重复上述测试处理,直至每条线段完全在窗口内或完全在窗口外。
Liang-Barsky算法
该算法由梁友栋、Barsky分别独立发明,是目前最高效的直线段裁剪算法。
基本思想:把直线看成是一条有方向的线段,把窗口的四条边及其延长线分成两类:入边和出边
入边:左边界和下边界------从裁剪框外向裁剪框内
出边:右边界和上边界------从裁剪框内向裁剪框外
任意直线段I(x1,y1)J(x2,y2 )的参数方程:
,其中0<=u<=1.
给定裁剪窗口:

如果任一点在窗口内, 则有:
上述关系可用4个不等式表达:
简记为:,其中:
几点说明:
- 取“=”时求得的u对应的是直线不窗口边界的交点
- 1、2、3、4分别对应左、右、下、上边界
- u=0和1时分别对应直线的起点和终点
那么,裁剪后的两端点是哪些点?

Uone> Utwo表明:没有线段在矩形内。
下图说明了,当PK为0时的特殊情况处理:

以下是Liang-Barsky算法代码的一个C++示例:
// Liang--Barsky line-clipping algorithm
#include<iostream>
#include<graphics.h>
#include<math.h>
using namespace std;
// this function gives the maximum
float maxi(float arr[],int n) {
float m = 0;
for (int i = 0; i < n; ++i)
if (m < arr[i])
m = arr[i];
return m;
}
// this function gives the minimum
float mini(float arr[], int n) {
float m = 1;
for (int i = 0; i < n; ++i)
if (m > arr[i])
m = arr[i];
return m;
}
void liang_barsky_clipper(float xmin, float ymin, float xmax, float ymax,
float x1, float y1, float x2, float y2) {
// defining variables
float p1 = -(x2 - x1);
float p2 = -p1;
float p3 = -(y2 - y1);
float p4 = -p3;
float q1 = x1 - xmin;
float q2 = xmax - x1;
float q3 = y1 - ymin;
float q4 = ymax - y1;
float posarr[5], negarr[5];
int posind = 1, negind = 1;
posarr[0] = 1;
negarr[0] = 0;
rectangle(xmin, 467 - ymin, xmax, 467 - ymax); // drawing the clipping window
if ((p1 == 0 && q1 < 0) || (p3 == 0 && q3 < 0)) {
outtextxy(80, 80, "Line is parallel to clipping window!");
return;
}
if (p1 != 0) {
float r1 = q1 / p1;
float r2 = q2 / p2;
if (p1 < 0) {
negarr[negind++] = r1; // for negative p1, add it to negative array
posarr[posind++] = r2; // and add p2 to positive array
} else {
negarr[negind++] = r2;
posarr[posind++] = r1;
}
}
if (p3 != 0) {
float r3 = q3 / p3;
float r4 = q4 / p4;
if (p3 < 0) {
negarr[negind++] = r3;
posarr[posind++] = r4;
} else {
negarr[negind++] = r4;
posarr[posind++] = r3;
}
}
float xn1, yn1, xn2, yn2;
float rn1, rn2;
rn1 = maxi(negarr, negind); // maximum of negative array
rn2 = mini(posarr, posind); // minimum of positive array
xn1 = x1 + p2 * rn1;
yn1 = y1 + p4 * rn1; // computing new points
xn2 = x1 + p2 * rn2;
yn2 = y1 + p4 * rn2;
setcolor(CYAN);
line(xn1, 467 - yn1, xn2, 467 - yn2); // the drawing the new line
setlinestyle(1, 1, 0);
line(x1, 467 - y1, xn1, 467 - yn1);
line(x2, 467 - y2, xn2, 467 - yn2);
}
int main() {
cout << "\nLiang-barsky line clipping";
cout << "\nThe system window outlay is: (0,0) at bottom left and (631, 467) at top right";
cout << "\nEnter the co-ordinates of the window(wxmin, wxmax, wymin, wymax):";
float xmin, xmax, ymin, ymax;
cin >> xmin >> ymin >> xmax >> ymax;
cout << "\nEnter the end points of the line (x1, y1) and (x2, y2):";
float x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
int gd = DETECT, gm;
// using the winbgim library for C++, initializing the graphics mode
initgraph(&gd, &gm, "");
liang_barsky_clipper(xmin, ymin, xmax, ymax, x1, y1, x2, y2);
getch();
closegraph();
}
智能推荐
GAMES101-现代计算机图形学学习笔记(2)作业1
前言 作业0 本篇继续更新作业1相关,本专栏预计2个星期内搞定。 作业1相关链接 games的作业1链接 我的源码 作业1简述 模拟基于CPU的光栅化渲染器 绘制要求中的三角形 作业1相关知识笔记 2D仿射变换和3D仿射变换矩阵推导 坐标系转化 视口变换 正交投影与透视投影 屏幕像素表示 光栅化算法: 直线:DDA数值微分算法、中点Bresenham算法 三角形:BoundingBox 作业1思路...
GAMES101-现代计算机图形学学习笔记(1)作业0
前言 本来是不想开这个系列的,因为这个课程作业大部分都完成了,奈何中间换了电脑,今天想回顾一下部分知识点,拿出旧的笔记本开虚拟机看搞得很麻烦,便想重新整理一遍笔记到网上+作业,也花不了太多时间,预计2个星期内完成。因为电脑是新电脑,一切都要从新配置,正好便利一下这个时间点想学习这门课的同学进行讨论和交流(论坛已经停止了提交作业)。 作业0相关链接 games的作业0链接 虚拟机链接,密码:92c9...
GAMES101-现代计算机图形学学习笔记(3)作业2
前言 上篇作业1 本篇继续更新作业2相关。 作业2相关链接 games的作业2链接 我的源码 作业2简述 在作业1的基础上栅格化一个三角形 判断点是否在三角形内 (提高)使用Supersampling抗锯齿 作业2相关知识笔记 光栅化算法:如何构建一个三角形的BoundingBox Depth buffer(Z-Buffering) Antialising Supersampling(MSAA) ...
GAMES101-现代计算机图形学学习笔记(5)作业4
前言 上篇作业3 本篇继续更新作业4相关内容 作业4相关链接 games的作业4链接 我的源码 作业4简述 实现贝塞尔曲线 (提高)对贝塞尔曲线实现反走样 作业4相关知识笔记 贝塞尔曲线相关 作业4思路 此处我考虑的是迭代。 结果: 提高部分: 计算相邻4个边缘点的像素颜色,此处有4种情况, 我们将点所在的像素颜色设为a(不变),那么根据距离再计算相邻3个像素的颜色。 对比:...
GAMES101-现代计算机图形学学习笔记(4)作业3
前言 上篇作业2 本篇将更新作业3相关内容 作业3相关链接 games的作业3链接 我的源码 作业3简述 插值计算 各种shader实现 作业3相关知识笔记 Barycentric Coordinates Blinn -Phong(Lambertian(Diffuse) Shading、Specular Shading、Ambient Shading) Flat shading、Gouraud s...
猜你喜欢
GAMES101-现代计算机图形学学习笔记(6)作业5
前言 由于上个月CSDN无故告诉我我的原创文章侵权(原创也侵权?),且我多日内多次申诉无效,于是我没有再更新自己的博客。今天我上CSDN的时候自己的文章(没有任何更改,莫名其妙就不侵权了?)又突然通过了,想着还是把这个系列更新完吧,不能半途而废。这个系列更新完后,后续将会更新在知乎上,这边只会看心情搬运了。 上篇作业4 本篇继续更新作业5相关内容 作业5相关链接 games的作业5链接 我的源码 ...
Mybatis源码的下载,搭建以及阅读源码的姿势
源码下载 mybatis的源码是在github上开源的,所以直接从github上搜索下载即可。 如上图,第一个就是mybatis3的源码项目,下面几个也是项目中常用的依赖项目,分页插件pagehelper,SSM项目需要引入的依赖mybatis-spring,mybatis-plus项目等。 当前最新版本是v3.5.5,可以选择合适的版本下载。我本地选择的是v3.5.4版本,小版本之间没有太大差异...
spring cloud + redis RedisTemplate Api搭建简单Demo
简介 Redis是一种NoSQL数据库,即非关系型数据库。redis是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,r...
c++在windows、linux下获取指定文件夹下所有文件名的方法
一般来说,获取指定文件夹下的所有文件名,用python是较为方便的,直接: import os files_name = os.listdir(“一个路径”) 但也有c++程序偶尔也有这个需求,下面就直接上c++在windows和linux去读取文件夹下文件名的方法,不同的系统代码上有一些差别 Windows(vs) vs的环境,主要是用到了头文件<io.h>,...
计算机图形学实验一绘制任意斜率的直线段
一、实验目的 (1)掌握任意斜率直线段的重点 Bresenham 扫描转换算法; (2)掌握 Cline 直线类的设计方法; (3)掌握状态栏编程方法。 二、实验步骤 (1)创建MFC应用程序 (2)定义CLine类 添加消息处理的处理程序 三、实验结果 四、实验体会 在本次实验中,通过不断的探索和实践,我学会了如何创建一个MFC应用程序,将理论运用于实践...
