初识消隐算法_艾孜尔江编撰
一、消隐
当我们观察空间任何一个不透明的物体时,只能看到该物体朝向我们的那些表面,其余的表面由于被物体所遮挡我们看不到。
若把可见的和不可见的线都画出来,对视觉会造成多义性。
会有后边两种情况
要消除二义性,就必须在绘制时消除被遮挡的不可见的线或面,习惯上称作消除隐藏线和隐藏面,简称为消隐。
消隐不仅与消隐对象有关,还与观察者的位置有关。
二、消隐的分类
1>按消隐对象分类
线消隐:消隐对象是物体的边
面消隐:消隐对象是物体上的面
2>按消隐空间分类
物体空间的消隐算法:
以场景中的物体为处理单位。假设场景中有k个物体,将其中一个物体与其余k-1个物体逐一比较,仅显示它可见表面已达到消隐的目的。(此类算法通常用于线框图的消隐!)
图像空间的消隐算法:
以屏幕窗口内的每个像素为处理单元。对屏幕上每个像素进行判断,决定哪个多边形在该像素可见(这类算法是消隐算法的主流)
三、图像空间的消隐算法:
1>Z-buffer算法
2>扫描线算法
3>Warnock消隐算法
画家算法:去除隐藏面最简单的算法
原理:若场景中有许多物体,就是先画远的物体,再画近的物体。这样一来,近的物体自然就会盖住远的物体。
但实际情况并不理想,在三维场景中,一个物体可能有些部分远,有些部分近,所以不管用什么顺序画,都无法得到正确的结果,所以画家算法只能解决简单场景的消隐问题。
Z-buffer算法
1、也称Z缓冲区算法和深度缓冲器算法(能跟踪屏幕上每个像素深度的算法),让计算机生成复杂图形成为可能。
2、该算法有帧缓冲器和深度缓冲器,对应两个数组:
Intensity(x,y)-属性数组(帧缓冲器),存储图像空间每个可见像素的光强或颜色
Depth(x,y)-深度数组(Z-buffer),存放图像空间每个可见像素的Z坐标。
Z-buffer保存的是经过投影变换后的z坐标,距离眼睛近的地方z坐标的分辨率比较大,远处的分辨率小。
3、Z-buffer算法思想
(开一个和帧缓存一样大小的存储空间,利用空间上的牺牲换区算法上的简洁)
(1)先将z缓冲器中各单元的初始值置为最小值
(2)当要改变某个像素的颜色值时,首先检查当前多边形的深度值是否大于该像素原来的深度值
(3)如果大于原来的z值,说明当前多边形更靠近观察点,用它的颜色替换像素原来的颜色。
4、伪代码
Z-buffer算法(){
帧缓存全置为背景色
深度缓存全置为最小z值(比如赋一个10^-8次方)
For(每一个多边形){
扫描转换该多边形
For(该多边形所覆盖的每个像素(x,y)){
计算该多边形在该像素的深度值Z(x,y);
If(Z(x,y)大于Z缓存在(x,y)的值){
把Z(x,y)存入Z缓存中(x,y)处
把多边形在(x,y)处的颜色值存入帧缓存的(x,y)处
}
}
}
}
5、优点:
(1)算法简单直观
(2)在像素级上以近物取代远物。与物体在屏幕上的出现顺序是无关紧要的,有利于硬件实现
(3)内存容量不再是问题后很受欢迎
6、缺点
(1)占空间大(因为要开一个和帧缓冲器一样大的数组,多了z缓存)
(2)没有利用图形的相关性和连续性(提高算法的效率要利用图形的相关性和连续性)
(3)是在像素级上的消隐算法
Z-buffer算法的改进(只用一个深度缓存变量zb的改进算法)
1、将缓存数组zb改为一个深度缓存变量zb
2、伪代码
Z-buffer算法(){
帧缓存全置为背景色
For(屏幕上的每个像素(i,j)){
深度缓存变量zb置最小值MinValue
For(多面体上的每个多边形Pk){
If(像素点(i,j)在Pk的投影多边形之内){
计算Pk在(i,j)处的深度值depth;
If(depth>zb){
Zb=depth;
Index=k;(记录多边形的序号)
}
}
}
If(zb!=MinValue)
计算多边形Pindex在交点(i,j)处的光照颜色并显示
}
}
关键问题:判断像素点(i,j)在Pk的投影多边形之内不容易
深度如何求?多边形的平面方程为ax+by+cz+d=0,可得出z值
点与多边形的包含性检测
一、射线法
1、由被测点P处向y=-无穷方向作射线
2、交点个数是奇数,则被测点在多边形内部,交点个数是偶数,则被测点在多边形外部
3、若射线正好经过多边形的顶点,则采用“左开右闭”的原则来实现
即:当射线与某边的顶点相交时,若边在射线的左侧,交点有效,计数;若边在射线的右侧,交点无效,不计数;
4、用射线法来判断一个点是否在多边形内的弊端:
(1)计算量大(因为要大量求交)
(2)不稳定(左开右闭有误差,在左边但由于误差算在了右边,不计数了)
二、弧长法
以P点为圆心作单位圆,把边投影到单位圆上,对应一段段弧长,规定逆时针为正,顺时针为负,计算弧长代数和
代数和为0,点在多边形外部;代数和为2π,点在多边形内部;代数和为π,点在多边形边上
算法为什么稳定?即使算出来后代数和不为0,而是0.1或0.2,那么基本可以断定这个点在外部,可以认为是有计算误差引起的。
但是算弧长并不容易,因此派生出一个新的方法-
以顶点符号为基础的弧长累加方法
1、不计算角度,用一个规定取代原先的计算
3、同一个象限认为是0,跨过一个象限是π/2,跨过两个象限是π。这样当要计算代数和的时候,就不用投影了,只要根据点所在的象限一下子就判断出多少度,这样几乎没什么计算量,只有一些简单的判断,效率高。
区间扫描线算法
1、该算法放弃了z-buffer算法,是一个新的算法,这个算法被认为是消隐算法中最快的之一,因为不管是哪一种z-buffer算法,都是在像素级上处理问题,每个像素都要进行判断,甚至一个像素要进行多次(一个像素可能会被多个多边形覆盖)
2、
3、主要思想:如果把扫描线和多边形的交点求出来,对每个区间,只要判断像素画什么颜色,那么整个区间的颜色都解决了(单位是区间)
4、如何确定小区间的颜色?
(1)小区间上没有任何多边形,如[a4,a5],用背景色显示
(2)小区间上只有一个多边形,如[a1,a2],显示该多边形的颜色
(3)小区间上存在两个或两个以上的多边形,如[a6,a7],必须通过深度测试判断哪个多边形可见
Warnock消隐算法
1、思想:采用分而治之的思想,利用了堆栈的数据结构(把物体投影到全屏幕窗口上,然后递归分割窗口,直到窗口内目标足够简单,可以显示为止)
2、什么情况,画面足够简单可以立即显示?
(1)窗口中仅包含一个多边形
(2)窗口与一个多边形相交,且窗口内无其它多边形
(3) 窗口被多边形包围
(4) 窗口与一个多边形分离(窗口显示背景色)
3、如何判别一个多边形和窗口是分离的?
4、如何判别一个多边形在窗口内?
5、算法步骤:
(1)如果窗口内没有物体则按背景色显示
(2)如果窗口内只有一个面,则把该面显示出来
(3)否则,窗口内含有两个以上的面,则把窗口等分成四个子窗口。对每个小窗口再做上述同样的处理。这样反复的进行下去。
光栅扫描算法小结
1、直线段的扫描转换算法
(1)DDA算法主要利用了直线的斜截式方程(y=kx+b),在这个算法里引用了增量的思想,结果把一个乘法变成了一个加法。
(2)中点法是采用的直线的一般式方程,也采用了增量的思想,比DDA算法的优点是采用了整数加法
(3)Bresenham算法也采用了增量和整数加法,优点是这个算法还能用于其它二次曲线
2、多边形的扫描转换和区域填充
把边界表示的多边形转换成由像素点表示的多边形
有四个步骤:求交、排序、配对、填色。为了避免求交运算,引入了一个新的思想-图形的连贯性。手段就是利用增量算法和特殊的数据结构,两个指针数组和两个指针链表。
3、直线和多边形裁剪
Cohen-Suther land算法和Liang-barsky算法
Cohen-Suther land核心为编码,把屏幕分成9个部分,用4个编码来描述这9个区域,通过4位编码的“与”“或”运算来判断直线段是否在窗口内或外。
Liang-barsky算法:
用参数方程表示
把被裁剪的直线段看成是一条有方向的边,把窗口的四条边分成两类:入边和出边
4、走样、反走样
用离散量表示连续量,有限的表示无限的会导致一些失真,这种现象成为走样。
反走样主要有三种方法:
提高分辨率、区域采样、加权区域采样
提高分辨率有物理限制,因为分辨率不能无限增加
区域采样可以把关键部位变得模糊一点,有颜色的过渡区域,产生好的视觉效果
加权区域时不但要考虑区域采样,而且要考虑不同区域的权重,用积分、滤波等技巧来做。
5、消隐
在绘制场景是消除被遮挡的不可见的线或面,称作消除隐藏线和隐藏面,简称为消隐。
按消隐空间分类:
(1)物体空间 以场景中的物体为处理单元
(2)图像空间 以屏幕窗口内的每个像素为处理单元
区间扫描线算法:发现扫描线和多边形的交点把扫描线分成若干区间,每个区间只有一个多边形可以显示。利用这个特点可以把逐点处理变成逐段处理,提高了算法效率。
Warnock消隐算法:采用了分而治之的思想,利用了堆栈的数据结构
核心思想:
1>增量
2>编码
3>整数、符号判别
4>图形连贯性
5>分而治之:把一个复杂对象进行分块,分到足够简单再进行处理
初识消隐算法_艾孜尔江编撰相关推荐
- 文曲星猜数字算法_艾孜尔江撰
//姓名:艾孜尔江·艾尔斯兰 学号:17081160 时间:2018年5月25日 21:33 #include<iostream> #include<ctime>//时间 #i ...
- JavaScript实现令人放松的小游戏_艾孜尔江撰
<html><head><!-- 由艾孜尔江·艾尔斯兰复现,转载或使用请注意标明出处.全程均使用鼠标交互,原游戏创作者不详,复现时有改动.使用时请在本地路径下放置一张玩家 ...
- 解决Pycharm装Illuminated Cloud之后无法创建项目的思路_艾孜尔江撰稿
解决Pycharm装Illuminated Cloud之后无法创建项目的思路_艾孜尔江撰稿 我是用的Pycharm版本是2017版,好久没用了,最近打开之后Pycharm自己弹出一个要装Illumin ...
- 用JavaScript实现贪吃蛇游戏_艾孜尔江撰
<!DOCTYPE html> <html><head><meta charset="utf-8" /><title>J ...
- JavaScript实现打砖块游戏_艾孜尔江撰
<!DOCTYPE html> <html> <!-- 使用原生的JavaScript复现打砖块游戏:代码在复现时有所改动.--><head><m ...
- Unity 3D基础入门编程_艾孜尔江撰稿
** 一. 版本控制 ** 目前流行的两大方式:SVN和Git: 前者采用增量式,后者采用快照式: 前者产生单点故障影响大. 安装git软件. 本地库--历史版本: 暂存区--临时存储: 工作区--写 ...
- C++图书管理系统_艾孜尔江撰
#include<iostream> #include<conio.h> //控制台数据输入输出的函数 #include<fstream>//文件流 #includ ...
- Git常用命令及其作用_艾孜尔江撰
撤销所有本次未提交的修改(相当于Tortoise Git的revert按钮): git checkout . 恢复某个已修改的文件(撤销未提交的修改): git checkout file-name ...
- 电脑无法识别U盘的解决方式集锦_艾孜尔江撰稿
**问题:**特定U盘无法被特定电脑识别 详述: 常年未使用的U盘在特定的一台电脑上插入时识别但在"此电脑"中无法找到. 该U盘在其他计算机设备上可以正常运行,在所谓的特定电脑上也 ...
最新文章
- LeetCode简单题之旋转字符串
- Scrum联盟发布2015年Scrum状况报告
- libopencv_core.so: file not recognized: File format not recognized
- 用二项逻辑斯蒂回归解决二分类问题
- Java实现算法导论中朴素字符串匹配算法
- python学号怎么编写_用python编写学生管理系统
- oracle避免同一sql多次查询,Oracle SQL - 在一个查询中生成一行答案的最简单方法,因此我不必多次运行查询?...
- HDUOJ---The number of divisors(约数) about Humble Numbers
- jquery弹出框样式大全_jQuery中w2ui是什么?-前端问答
- win10 mysql5.7.11_Windows10安装与配置MySQL-5.7.11
- 鸿蒙WLAN模组联网+解决在Visual Studio Code不能更改Linux文件的问题
- 360互联网技术训练营第七期 -“遇见”PIKA
- ❤️ Spring相关配置
- 《深度学习Python实践》第13章——审查回归算法
- Android中如何实现无缝切码流
- HTML弹窗上下一步,JS实现从网页顶部掉下弹出层效果的方法
- stm32f407与计算机的usb通讯,STM32F407 USB通信程序 USB Device 虚拟串口 CDC类 Cubemx生成...
- Youtube油管视频类别标签列表
- 调用Google翻译 语音接口
- UNREAL ENGINE 4.12 正式发布!下载地址