OpenGL 种子填充算法相同代码在 Linux 下正常运行,在 Windows 下爆栈或无法得到正确结果

2015-05-25 23:04:13 +08:00
 razrlele
用C++写的种子填充模拟程序,两个程序一个是递归的一个是非递归的,在Linux上运行完美(Archlinux,freeglut),两个程序都运行正常,效果图都如下:


在Windows 8.1 + Codeblocks 13.12 上运行程序结果不正确,如下图:

递归版本:



循环版本:



在Windows 8.1 + Visual Studio 2013 + freeglut 上运行程序爆栈,如下图:

递归版本:



循环版本:



程序源代码:

循环版本:

https://gist.github.com/razrLeLe/13e19da544f590b1b6b4

递归版本:

https://gist.github.com/razrLeLe/ed2ac2ffb937aceda8e6

感觉代码的核心部分应该是没有问题的,求OpenGL老司机带一脚,指点一下问题可能在哪里。。。
2061 次点击
所在节点    问与答
10 条回复
canautumn
2015-05-26 05:36:49 +08:00
不明觉厉,不过我在Mac下运行了你的程序,没出错不过结果和以上四个图都不一样,只涂了左半边多一点。
razrlele
2015-05-26 07:43:08 +08:00
@canautumn 是没有完全填充么?
canautumn
2015-05-26 08:51:20 +08:00
comicfans44
2015-05-26 08:59:35 +08:00
https://www.opengl.org/documentation/specs/version1.1/glspec1.1/node44.html#SECTION00630000000000000000

这个问题应该是你绘制点时使用的坐标不正确,原来的代码是绘制在整数坐标点上,导致相邻的两个像素都可能被填充成了newColor,后续readPixel读取时也就不准确了。浮点误差的积累就导致了readPixel一段读出来是oldColor,一段读出来是newColor,导致你的填充结果是一段有一段没有。

因此你的setPixel应该是

glVertex2f(x+0.5,y+0.5)


依靠读取帧缓存进行点判断很难保证不同平台的统一,至于linux和windows表现不同只能是因为边界条件下不同实现的表现不一致。
razrlele
2015-05-26 10:53:34 +08:00
@comicfans44

把setPixel改成了glVertex2f(x+0.5, y+0.5)在Windows下递归算法还是会爆栈,而循环算法则是错误结果(按道理把应该只会碰见黑色像素才会填充但是结果把红色边框也填充成绿色了,所以应该还是读取像素错误),与此同时在Linux下运行正确。

后来我还尝试直接使用实心矩形,Windows递归算法下依旧爆栈,并且跟边框多边形爆栈过程几乎一致(先不断地向上填充然后上半部分还没有填充完就爆栈),循环算法下则是没有出爆栈,最后结果也是成功填充,但是填充过程却不正确(左下部分最后填充,按道理应该是均匀渐渐填充的)。。。

期间还尝试直接避免浮点数,把所有的像素数据类型换成unsigned byte,然而并没有用。。。

能不能麻烦您再指导一下该如何正确地绘制坐标以及填充像素。。。谢谢!
razrlele
2015-05-26 11:28:37 +08:00
@comicfans44 目测是编译器的锅,各种CB可以跑VS不能跑。。。。
comicfans44
2015-05-26 12:35:07 +08:00
@razrlele 仔细观察填充过程,红色边框是没有填充成绿色的,因为你的draw_rec没有设定glColor,填充完点之后glColor还是点的颜色,所以画出来边框也是绿色了
comicfans44
2015-05-26 12:37:20 +08:00
@razrlele linux看以来边框没变色应该是没有触发重绘事件,没有重绘边框。不然也会变绿。你可以在绘制完拖动下窗口或者最大化最小化一下确认这个现象
comicfans44
2015-05-26 18:08:06 +08:00
@razrlele 指导是不敢说的,我也不是完全明白,遇到需要准确确定像素位置的情况,最好是去查opengl 的spec,主要是光栅化部分的说明,也就是之前链接的那部分。

楼主的主攻方向是什么?如果OpenGL只是用来画图表现结果,那我推荐你使用基于内存的填充和判断,最终只用OpenGL把结果画出来(这样可以避免OpenGL相关的很多细节问题)

如果主攻的是计算机图形学,那建议配合一本按照OpenGL讲计算机图形学的书来对照学习。正确绘制坐标的部分主要是参考 矩阵变换,透视投影,归一化,OpenGL的光栅化spec这些内容。将你的绘制坐标按照浮点数带入公示计算,相信你可以明确知道你画的点最终出现在屏幕的哪个像素上。

apitrace是一个很好的跟踪工具,用它来跟踪你的程序,可以回放到任意一个OpenGL函数上查看结果
razrlele
2015-05-26 22:26:02 +08:00
@comicfans44

其实这只是一个CS小本图形学实验课作业罢了。。。

自己有买蓝宝书。。。但是翻了一下感觉似乎没有glReadPixel这些函数(是太老太过时了?)。。。最后上OpenGLl的man page去找也没有找到相关细节问题(当然也有可能看的不仔细),现在我感觉问题有可能出现在环境配置相关,因为同是Windows系统下结果也会五花八门,我断点调试之后发现问题的关键都是各种诡异的像素读取错误。。。

基于内存的填充和判断还没有尝试过,这个我再去研究一下。。。

这两天是真心被OpenGL折腾怕了 冏rz~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/193692

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX