[OpenGL][SharpGL]用Polygon Offset解决z-fighting和stitching问题
[OpenGL][SharpGL]用Polygon Offset解决z-fighting和stitching问题
本文参考了(http://www.zeuscmd.com/tutorials/opengl/15-PolygonOffset.php),用SharpGL重写了示例代码,您可以点击文末的链接下载。
什么是stitching和z-fighting
在OpenGL中,如果想绘制一个多边形同时绘制其边界,可是先使用多边形模式GL_FILL绘制物体,然后使用多边形模式GL_LINE和不同的颜色再次绘制这个多边形。但是由于直线和多边形的光栅化方式不同,导致位于同一位置的多边形和直线的深度值并不相同,进而导致直线有时在多边形的里面,有时在多边形的外面,这种现象就是"Stiching"。
而Z-fighting主要是指当两个面共面时,二者的深度值一样,深度缓冲就不能清楚的将它们两者分离开来,位于后面的图元上的一些像素就会被渲染到前面的图元上,最终导致图象在帧与帧之间产生微弱的闪光。
(上面这几段是从(http://blog.csdn.net/oglmatrix/article/details/1793074)复制来的。)

Polygon Offset效果图
解决这两个问题的方法就是使用Polygon Offset,当然你也可以使用模板测试,但Polygon Offset的速度会比模板缓存快。
下面就是stitching的情况。

下面就是z-fighting的情况。

而理想的效果是这样的:

下面是下文将介绍的Demo。

这是没有使用Polygon Offset的情况。

这是使用了Polygon Offset的情况。
如何使用Polygon Offset
下面用上图所示的模型来演示如何使用Polygon Offset。我们要画一个立方体,立方体的黑色线框,还有3个正方形。
Offset开关
我们用一个bool变量记录是否启用Polygon Offset。这样就可以看清楚这项技术的效果了。
/// <summary>
/// determins whether enalbe or disable polygon offset.
/// </summary>
private bool offset = true;
用立方体演示stitching
我们画一个立方体和它的线条,用于演示stitching。
void drawBox(OpenGL gl)
{
gl.Begin(OpenGL.GL_QUADS);
// FRONT
gl.Vertex(-0.5f, -0.5f, 0.5f);
gl.Vertex(0.5f, -0.5f, 0.5f);
gl.Vertex(0.5f, 0.5f, 0.5f);
gl.Vertex(-0.5f, 0.5f, 0.5f);
// BACK
gl.Vertex(-0.5f, -0.5f, -0.5f);
gl.Vertex(-0.5f, 0.5f, -0.5f);
gl.Vertex(0.5f, 0.5f, -0.5f);
gl.Vertex(0.5f, -0.5f, -0.5f);
// LEFT
gl.Vertex(-0.5f, -0.5f, 0.5f);
gl.Vertex(-0.5f, 0.5f, 0.5f);
gl.Vertex(-0.5f, 0.5f, -0.5f);
gl.Vertex(-0.5f, -0.5f, -0.5f);
// RIGHT
gl.Vertex(0.5f, -0.5f, -0.5f);
gl.Vertex(0.5f, 0.5f, -0.5f);
gl.Vertex(0.5f, 0.5f, 0.5f);
gl.Vertex(0.5f, -0.5f, 0.5f);
// TOP
gl.Vertex(-0.5f, 0.5f, 0.5f);
gl.Vertex(0.5f, 0.5f, 0.5f);
gl.Vertex(0.5f, 0.5f, -0.5f);
gl.Vertex(-0.5f, 0.5f, -0.5f);
// BOTTOM
gl.Vertex(-0.5f, -0.5f, 0.5f);
gl.Vertex(-0.5f, -0.5f, -0.5f);
gl.Vertex(0.5f, -0.5f, -0.5f);
gl.Vertex(0.5f, -0.5f, 0.5f);
gl.End();
}
用正方形演示z-fighting
我们在立方体的一个面上,画几个正方形,用于演示z-fighting。
void drawPolygon(OpenGL gl)
{
gl.Begin(OpenGL.GL_QUADS);
gl.Vertex(-0.5f, -0.5f, 0.0f);
gl.Vertex(0.5f, -0.5f, 0.0f);
gl.Vertex(0.5f, 0.5f, 0.0f);
gl.Vertex(-0.5f, 0.5f, 0.0f);
gl.End();
}
启用Polygon Offset
Polygon Offset有多种使用方式。其中之一就是把立方体推远一点点,这样,线框和正方形就与立方体有了间隔,就不会产生干涉。(我的理解是,在执行深度测试前立方体的深度值被稍微增加了一点点,于是就跟线框区分开了。)
启用Polygon Offset有三个可选参数(GL_POLYGON_OFFSET_POINT, GL_POLYGON_OFFSET_LINE 和GL_POLYGON_OFFSET_FILL),分别对应3种光栅化模式(GL_POINT, GL_LINE 和GL_FILL)。
首先来渲染立方体,我们用GL_POLYGON_OFFSET_FILL来启用Polygon Offset。
if (offset)
{
gl.Enable(OpenGL.GL_POLYGON_OFFSET_FILL);
指定偏移量
启用了Polygon Offset,那么到底要把立方体推远多少呢?这需要用glPolygonOffset来指定。glPolygonOffset需要2个参数:GLfloat factor 和GLfloat units。
每一个Fragment的深度值都会增加如下所示的偏移量:
offset = (m * factor) + (r * units)
m是多边形的深度的斜率(在光栅化阶段计算得出)中的最大值。这句话难以理解,你只需知道,一个多边形越是与近裁剪面(near clipping plan)平行,m就越接近0。
r是能产生在窗口坐标系的深度值中可分辨的差异的最小值,r是由具体实现OpenGL的平台指定的一个常量。
一个大于0的offset 会把模型推到离你(摄像机)更远一点的位置,相应地,一个小于0的offset 会把模型拉近。
如果想要非常好地使用Polygon Offset,你需要做一些数学上的研究。不过一般而言,只需把1.0和0.0这样简单的值赋给glPolygonOffset即可满足需要。
我们要把立方体推远一点,所以
gl.PolygonOffset(1.0f, 1.0f);
}
然后,我们绘制立方体,并关闭Polygon Offset。
gl.Color(1.0f, 0.0f, 0.0f);
gl.PolygonMode(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_FILL);
drawBox(gl); if (offset)
gl.Disable(OpenGL.GL_POLYGON_OFFSET_FILL);
绘制正方形
我们已经推远了立方体,所以原本在立方体平面上的绿色和黄色正方形就没有z-fighting现象了。直接绘制即可。
gl.Color(0.0f, 1.0f, 0.0f);
gl.PushMatrix();
gl.Translate(-0.25f, -0.25f, 0.5f);
gl.Scale(0.5f, 0.5f, 0.5f);
drawPolygon(gl);
gl.PopMatrix(); gl.Color(1.0f, 1.0f, 0.0f);
gl.PushMatrix();
gl.Translate(0.25f, 0.25f, 0.5f);
gl.Scale(0.5f, 0.5f, 0.5f);
drawPolygon(gl);
gl.PopMatrix();
注意,绿色和黄色正方形两者之间没有重叠的部分,所以不会有z-fighting现象。
但是蓝色正方形与绿色、黄色正方形都有重叠,所以会有z-fighting现象。为避免此现象,我们把-1.0赋予glPolygonOffset,即拉近蓝色正方形。
if (offset)
{
gl.Enable(OpenGL.GL_POLYGON_OFFSET_FILL);
gl.PolygonOffset(-1.0f, -1.0f);
} gl.Color(0.0f, 0.0f, 1.0f);
gl.PushMatrix();
gl.Translate(0.0f, 0.0f, 0.5f);
gl.Scale(0.5f, 0.5f, 0.5f);
drawPolygon(gl);
gl.PopMatrix(); if (offset)
gl.Disable(OpenGL.GL_POLYGON_OFFSET_FILL);
绘制立方体的线框
如果直接绘制立方体的线框,线框会与立方体产生stitching现象。所以,如同拉近蓝色正方形一样,我们也把线框拉近一点。不同的是,我们把GL_POLYGON_OFFSET_LINE赋予glEnable。
if (offset)
{
gl.Enable(OpenGL.GL_POLYGON_OFFSET_LINE);
gl.PolygonOffset(-1.0f, -1.0f);
} gl.Color(0.0f, 0.0f, 0.0f);
gl.PolygonMode(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_LINE);
drawBox(gl); if (offset)
gl.Disable(OpenGL.GL_POLYGON_OFFSET_LINE);
启用\禁用Polygon Offset
我们用A键开控制是否启用Polygon Offset功能。
void openGLControl_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.A)
{
offset = !offset;
}
}
到此,Demo讲解完毕,您可以在上文查看启用\禁用Polygon Offset的效果。
[OpenGL][SharpGL]用Polygon Offset解决z-fighting和stitching问题的更多相关文章
- opengl Polygon Offset
http://www.cnblogs.com/bitzhuwei/archive/2015/06/12/4571539.html#_label2 启用了Polygon Offset,那么到底要把立方体 ...
- Z - Fighting 和 Depth-bias
Depth-bias操作在clipping之后进行实施,所以depth-bias对几何clipping没有影响. 另外需要注意的是:对一个给定体元(primitive),bias值是一个常量,在进行差 ...
- 【OpenGL(SharpGL)】支持任意相机可平移缩放的轨迹球实现
[OpenGL(SharpGL)]支持任意相机可平移缩放的轨迹球 (本文PDF版在这里.) 在3D程序中,轨迹球(ArcBall)可以让你只用鼠标来控制模型(旋转),便于观察.在这里(http://w ...
- 【原创】pads layout 画多边形copper,出现Self-Intersecting Polygon,解决办法
在做线性位移传感器的电路板时,需要在一个很小的多边形Copper操作,总是提示“Self-Intersecting Polygon”报错,意思是outline线自身交叉,换句话说就是线宽与多边形尺寸没 ...
- Kafka+SparkStreaming+Zookeeper(ZK存储Offset,解决checkpoint问题)
创建一个topic ./kafka-topics.sh --create --zookeeper 192.168.1.244:2181,192.168.1.245:2181,192.168.1.246 ...
- 使用 C# 和 OpenGL (SharpGL) 实现的一个简易画图版
原文地址:https://billc.io/2019/10/fpainter/ 计算机图形学的第一个大作业是用 OpenGL 或 DirectX3d 实现一个平面的画图,应当具备直线和圆形的功能.正好 ...
- Polygon Offset
https://www.cnblogs.com/bitzhuwei/p/polygon-offset-for-stitching-andz-fighting.html 一个大于0的offset 会把模 ...
- OpenSSL.Net 在生产环境中无法正常加载的原因分析与解决 z
http://blog.csdn.net/wangjia184/article/details/6990098 http://www.openssl.org/ 在本地测试好好的代码部署到生产环境后,遇 ...
- Z Fighting Problem
Here is a video about unity depth shader workarounds: http://www.burgzergarcade.com/tutorials/game-e ...
随机推荐
- linux中find批量删除空文件夹
空文件夹 列出用find 删除管道即可 find -type d -empty | xargs -n 1 rm -rf 注意最后不能rm -f,这样删不了目录,必须-r
- ring3硬件断点
4个断点寄存器DR0~DR3用来设置断点的线性地址. DR6为状态寄存器,DR7为控制寄存器. DR4和DR5保留.当CR4.DE==1时,访问DR4和DR5产生#UD异常:IF CR4.DE==0, ...
- python 学习第二十一天,django知识(三)
一,django的url路由系统总结 1,url(/index/,函数或者类) 2,url(/index/(\d+), 函数或者类) 3,url(/index/(?P<nid>\d+),函 ...
- Terminology: Sandbox
In Comupter Secuity: from https://en.wikipedia.org/wiki/Sandbox_(computer_security) In computer secu ...
- [译]App Framework 2.1 (2)之 About
英文原文在此:http://app-framework-software.intel.com/documentation.php#App Framework/af_about App Framewor ...
- jquery+bootstrap实现tab切换, 每次切换时都请求数据, 点击提交分别向不同的地址提交数据
今天一个朋友叫帮做一个tab切换, 每一个tab内容区域都是从后台取出的数据, 这些数据要用表格的形式显示处理, 并且表格的内容区域可以修改, 如下所示: 例子查看请演示查看. 截图如图所示: 实现步 ...
- 理解storm的ACKER机制原理
一.简介: storm中有一个很重要的特性: 保证发出的每个tuple都会被完整处理.一个tuple被完全处理的意思是: 这个tuple以及由这个tuple所产生的所有的子tuple都被成 ...
- [转]Android Studio 里搭建自动化测试框架Robotium
Android的自动化测试框架可选择的不多,后来选了Robotium(https://code.google.com/p/robotium/),它的语法及易用性挺像我们用在iOS里的KIF. 官方文档 ...
- Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...
- java反射学习之二万能EXCEL导出
一.EXCEL导出的实现过程 假设有一个对象的集合,现在需要将此集合内的所有对象导出到EXCEL中,对象有N个属性:那么我们实现的方式是这样的: 循环这个集合,在循环集合中某个对象的所有属性,将这个对 ...