Pillow简介

来源 :电脑知识与技术 | 被引量 : 0次 | 上传用户:yufengdetianxia
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘要:本文介绍了轻量级多边形建模工具Pillow的编写过程和大体结构。
  关键词:计算机图形;多边形建模;细分算法
  中图分类号:TP302 文献标识码:A文章编号:1009-3044(2007)03-10835-02
  
  1 引言
  
  Pillow是一个我编写的轻量级多边形3D建模程序。目前,这个程序还处于初级阶段,只实现了一些基本的多边形建模操作,比如对点、边、面、体的挪动旋转以及缩放操作、删除、焊接、切割等等。另外还有catmull-clark细分。出于对速度的考虑,目前人为地限定在最大5次细分,实际上细分的次数可以不限。因为这个程序还在起步阶段,仍存在很多需要解决的问题,但是不管怎么说是个不错的开始。据我所知,許多小规模的建模工具都要开发很多年,而我才搞了两个多月。
  
  2 最初的设想
  
  大概是在2004年10月,我开始有自己编一个建模工具的想法。当时是要学DirectX,我觉得学编程必须要动手才行,所以想到写个像silo的程序。因为我觉得silo是一个面向使用的程序,而且是所有3D建模工具里规模比较小的。今年7月大学毕业后,我开始写这个程序。
  因为最初是为了练习DirectX,所以最早是想用c#和managed directx来写。当时还用过一个truevision3d的引擎。原因很明显,引擎里屏幕拾取等操作已经都给你做好了。但是因为引擎的数据结构特别大,效率很低,所以后来我就直接用directx来编了。而我现在的这个程序则是重新用c++和opengl写的。最开始有人问我为什么不选择opengl,我的回答是每一个图形库都很有学问,一个尚且学不好,怎么能顾得上学另一个。不过自从接触过opengl之后,我觉得opengl没有directx封装的利害,感觉用起来很直接。我很喜欢opengl,用c++的目的首先是因为要用opengl。当然,tao framework我也试过,不理想。第二个原因是因为效率,交互性强的程序太需要效率了。第三个原因是c++应该是编图形程序的首选语言。至于程序的界面,我选择了wxWidgets。我编程的时候一般都非常在意界面。我认为外观设计不是什么无足轻重的东西,如果苹果公司没有它的工业设计,这样一个不兼容的怪胎早就被淘汰了。不过很遗憾,我找不到满足我要求的c++界面库。我希望能够有一个跨平台,最好开源,可以换肤,控件比较丰富的界面库,但是没有。编这个程序的时候我先后用了cegui,wxWidgets,qt4,但哪个都不满意。最后选择wxWidgets是因为silo也用它。
  
  3 关于程序结构
  
  我的程序大体分成了三个层次,界面层负责和使用者交互,并且把操作的结果显示出来。中间的控制层负责管理整个场景,负责将图形的操作转换成对于数据的操作。这部分实际上是整个程序的核心。最里面的是数据层,存储的是场景的图形数据。场景管理器和数据层之间的交互被严格定义为一组命令,并且每一个命令都会被一个叫做历史管理器的东西记录下来,便于随时将操作进行回退。在图中,蓝颜色的箭头表示的是命令的走向,紫颜色表示的是记录命令,红颜色是显示数据的走向。
  目前我的程序还不具备undo和redo的功能,但实际上我在程序中已经实现了。但是和界面结合的时候我没有把它添上,因为这部分程序写得有点乱。之前对于如何实现程序的核心部分,我考虑了很长时间,但如何与界面结合,我考虑的不多。另外一个原因是我没有找到一个得心应手的界面包,我尝试了很多的界面方案,几乎每一种界面都有自己的一套编程风格。由于历史记录是比较容易出问题的部分,尤其是容易内存泄露,我因此暂时没有把它包含进来。
  当初要实现undo和redo的时候我想到要用命令的方式,每个命令都有个逆命令,操作的时候记录每条命令,需要回退的时候再调用相应的逆命令。但是很多操作,比如说求平均,是没有逆命令的。把求平均之前的情况都记录下来,显然也是个比较笨的办法。后来我想到把操作分层,因为不管一个图形操作的过程有多么复杂,归根结底都是要改变数据,改变数据的方式无非就是添加、删除和改动这几种,所以我只要记录这些简单的操作,就可以应对复杂的图形操作了。实际上,在我的程序中定义的简单操作有几十种,并不只是添加、删除和修改这几种。
  图3
  什么是历史管理器呢,实际上是一个队列和栈的结构,命令被压入一个叫undo的队列头部,如果超过了队列的长度,则从队列的尾部直接抛弃。如果用户想要回退一步操作,就直接弹出在队列头部的一个命令进行回退,同时把这个命令翻译成逆命令放到redo中去。这个redo是一个栈的结构,如果要重做这步操作就弹出redo栈,执行,然后把命令翻译成逆命令再次放到undo队列中。
  如何防止内存泄露,我的设计是这样的:把所有在堆中的数据的指针进行统一管理,这个结构我叫做data pool,实际上是个动态数组。任何其它的操作只能够引用这些数据,引用是通过数组的下标,而不是指针。释放指针由这个data pool统一进行。有两种方式,一种是直接释放,另一种是当需要记录删除操作的时候,把这个指针交给历史管理器,然后当历史管理器也不需要这个指针的时候,再释放掉它的空间。这样就可以防止指针已经丢失但空间仍没有释放的情况,因为任何时候被分配的空间都至少在data pool中保留了一个指向它的指针。然后通过data pool释放这个指针,就可以释放掉这个空间。
  细分算法是多边形建模工具的关键。商业的多边形建模工具都具备很好的交互性,用户在模型细分的情况下进行编辑仍然可以立刻得到效果,这就要求细分算法的速度比较快。从理论上讲,细分算法由增加细节和求取平均两步来完成。但是在实际的操作中,严格按照这两步来操作并不明智,因为这样会增加遍历整个数据的次数。因为你可能需要分别遍历所有的点,边和面的数据。在我的程序中,我想办法只遍历一次所有的面,在遍历过程中计算好所有的数据。另外一点就是要尽量减少重复计算,比如:现在要遍历所有的面,对于每个面,都将它的邻接边一分为二,这样对于两个面的公共边,有可能出现重复计算的情况。我曾经看到subdivision.org上的专家建议用哈希表来避免重复,但我认为这个方法也不太好。在我的数据结构中,每一个图形元素都有一个细分编号。每一次细分开始的时候,程序都生成一个新的细分的编号,遍历的过程中,不断地比较这个编号和图形元素拥有的编号是否一致,如果不一致则认为是第一次运算进行处理,然后将这个图形元素的编号更新成新生成的细分编号。另外,很多时候使用者习惯先进行细分,然后再调整控制点来改变造型。这就需要增加交互性。我采用的方法就是局部的细分算法。当使用者选定一些控制点准备操作的时候,我的程序要先判断在当前的细分层次下的操作范围并且缓存,然后当操作发生的时候,只对缓存的面进行更新。
  
  4 结束语
  
  最初我把我编这个程序的想法告诉别人时,有人问我,这个程序到底有什么创新的地方,既然天下多边形建模工具已经那么多了。应该说目前还没有,但是以后会有的。现在这个程序虽然很普通,但是这是今后创新的一个平台,未来有可能在这个基础上做一些真正自己的东西。通过编这个程序我学到了不少东西,也多了不少认识。我感觉c++是一个陷阱,确切地说指针是陷阱,用的时候觉得很方便,肆无忌惮,但是当程序大到一定程度,就会突然发现它已经是千疮百孔了,处处都有可能造成泄露。但是一个图形的程序又怎能不用指针呢。我也想过把它都换成smart pointer,但是不知道效率上会打多大的折扣。
  
  5 操作方法简介
  
  下面介绍一下这个建模程序Pillow的基本操作方法。模型做的比较粗糙,上面這幅作品是完成之后经3D Max简单渲染的效果:
  Pillow是一个模仿silo的程序,因而在操作方法上与其高度一致。silo把建模的操作合理分配到左右手,我觉得能很好地提高工作的效率。简单的来说是这样的:
  alt健加鼠标左键拖动用来旋转视角
  alt键加鼠标中建拖动用来平移视角
  alt键加鼠标滚轮用来缩放视角
  鼠标左键拖动用来单面选择
  鼠标中键拖动用来双面选择
  c为增加细分
  v为减少细分
  ctrl为沿视平面进行平移,前提是选择了物体
  shift为增加选择内容
  z为突出面或者边
  w为移动模式
  e为旋转模式
  r为缩放模式
  1-7为切换不同的视角
  delete为移除点或边,其中点只能是有两个邻接边的点,这个操作目前有bug。
  所有的操作都集中在菜单里面,而编辑窗口有几个我用OpenGL做的工具栏,这里面都是最常用的一些操作。把界面设计成这样是因为我曾经用过的一个silo的界面,记得当时我在cgfinal发过。silo可以自定义部分界面以及快捷键,但是我这个还不行。左侧的按钮选择编辑物体的编辑层次。右面的是选择窗口的层次。上面一条是文件操作,建立新物体和编辑新物体,还有截图快捷键和帮助。下面是选择显示的形式和选择照相机的形式。
  建模的过程:
  我做模型的时候比较喜欢box modelling的方式,总是从一个盒子的形状开始,这样比较容易从大局上把握形状,但是也容易让人忽视掉细节。我做模型的时候比较喜欢用参考图。关于 参考图,我的经验是从电影电视剧或者mv中去找,因为这样比较容易找到不同角度的参考,而如果直接去找照片的话,正面照好找,侧面照就比较少了。有了参考 图之后,要对正面和侧面的图进行一定的缩放和旋转,使得它们的比例一致。在这个过程中我比较喜欢用photoshop的标尺,在photoshop中让两 个参考图的下巴和头顶处于水平,鼻尖和眼睛的高度一样,还有嘴角和耳根也要一样。我的这个侧面参考图不完整,所以我用鼠标补了一些脑袋。对齐之后剪裁成两个高度一致的图。
  然后开始建模。首先就是要在Pillow中指定参考图(option->set viewport image),silo中可以直接用鼠标来调节参考图位置,但是我这个还不行,需要手动输入位置。然后新建一个box(create-> cube)。然后对这个方盒子分别在前视图和侧视图中进行调节,使得在前视图近似为头的一半大小,在侧视图中刚好覆盖头部。调整好之后在透视图中删除中间 的面,也就是说我们要镜像复制一个当前的模型,因为脸是对称的。点击菜单上的(create->mirror instance)复制出镜像,对称平面为默认。
  然后按图进行切割,这个切割线分别对应了头的眼睛位置和耳朵的位置。目前Pillow只支持在一个边的中间进行切割,其实核心的程序允许在任意位置切割,但 是和界面整合的时候我偷了点懒。然后将显示模式切换到线框模式,分别在前视图和侧视图中调节点的位置,使得这个造型和参考图近似。
  可以随时对模型细分进行观察,目前Pillow在编辑模型的时候还不能实时地更新法线,主要是我还没有想好有什么快的局部更新法线的算法。所以如果想观察光照效果需要从 菜单执行更新法线的命令(modify->update normal)。然后新增加一条竖线,这条线要对应人的瞳孔和嘴角。
  然后要不断的调节点的位置,使得模型接近参考图。现在继续切割出两条线,一条是在额头,另一条在嘴的位置。同样要在各个视图中调节位置。让线条过渡自然一点。
  然后横向切割出鼻子,并且调节。随时可以细分进行观察。在调节好点的位置之后要切割出眼睛和嘴的大致形状。
  然后在视图中调节,同时增加眼睛的细节。继续增加细节和调节点。调节点,可以用线框模式来显示,这样比较便于观察。
  仍然是增加细节和调节点的工作。继续增加细节,但是这个时候要清楚线条的走向。建模有个原则--线条要符合肌肉的走向,就是图中我用红线画出来的线条。眼睛和嘴的线条要形成一个圈。
  在增加线条的同时要不断切割出新的边,但是同时还要删除旧的边。因为我们是盒子建模,一开始的边都是横平竖直的,这个会对我们的最终模型产生一定影响。所谓盒子建模不容易把握细节,很大程度上就是这个原因。其实我觉得懂得如何删要比懂得如何添要重要的多。
  如果你最后的成品依然有很多横平竖直的线条,那一定是很失败的作品。继续添加鼻翼附近的线条,这样也是为了增加嘴部的细节。
  当嘴的细节到达一定的程度就可以进一步刻画了。要做出黑人厚嘴唇的效果。在眼睛的位置切割出更多的边。
  在鼻子上切割更多的边,这个是为了增加细节好开出鼻孔。现在可以依据参考图开出鼻孔了。首先切割出一个矩形的区域。
  在这个区域上使用突出(modify->extrude)几次,做出洞来,然后要调节点。时不时细分一下来观看效果。继续增加鼻子的细节,一方面要做出鼻翼凸起的效果,另一方面是修改三角面,尽量把三角面改成四边形。
  继续制作鼻翼。现在增加眼睛周围的圈数,增加细节准备做眼睛。
  不断调整眼睛周围点的位置,然后选中眼睛上的面删除。删除之后就形成了眼眶。
  如果把握不好眼睛的造型,可以生成一个球体作为眼球,放在眼睛的后面作为依据。细致刻画眼睑的效果。
  选中眼睛镂空的一圈边,然后将视角转动到头的里侧,按住z键,拖拽出眼睛没入脑袋的部分。继续调节点的位置,让模型有厚度,不是像面具一样只是一个面片。
  这是目前侧视图的效果。将嘴上的一组面删除,将嘴裂开,同时增加更多的边,做出嘴唇鼓起的效果。
  要在侧视图中进行调节,细分观察效果。做出镜像的效果观察。
  调节脸型鼻子和嘴上的点。和做眼睛类似,选择嘴镂空的一圈边之后将视图转动到脑袋里侧,按住z键突出处一些面。
  然后调节这些面。现在要做出下巴骨,不知道应该怎么说。让这个地方的线条更加明显,这个线条要成直角。
  如图红色的地方,让点往里缩,这样可以显现出下巴骨的线条。然后要制作脖子了,选择脖子位置的面删除。然后再脖子镂空的地方,选择一圈边进行突出。
  突出以后在前侧视图调节点的位置,使得它们契合参考图。不要忘了在透视图中进行调节。注意途中红线的位置,这个地方要做出一个凸起。
  如图增加细节,做出凸起的效果。调节,细分。
  换个角度。复制出镜像来观察。
  下面做耳朵,在侧视图中删除耳朵位置上的面。在侧视图中调整出一个耳朵的轮廓。选择一个边突出一小部分,然后以这个突出的部分为基础按照图中的顺序继续突出记下,形成一个耳朵的轮廓。
  还要到头视图里面调整这个轮廓的位置。然后细分进行观察。
  这个地方我做的比较糙。实际上应该做出耳朵里面的褶皱,但是我偷懒了。我这里简单的把耳朵的轮廓进行了延展,然后焊接,也就是把上面的框框给封起来了。不要忘了调整耳根后面的点,这个地方的点要往里收缩。
  这个时候要把脑袋后面一些刚才忽略的细节给补上。基本就算完成了,然后细分一下,使一个重新定义控制点(subdivision->redefine control mesh),把模型定格在细分的状态,如图:
  详细信息可访问我的博客:http://billconan.blogspot.com/
  本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。
其他文献
摘要:基于XML的中间件技术与知识集成相结合,设计了一个基于XML的知识集成中间件系统结构,并详细讨论了系统主要功能模塊的实现方法。  关键词:知识集成;中间件系统;XML  中图分类号:TP311  文献标识码:A  文章编号:1009-3044(2006)29-0137-03
期刊
摘要:自然景物的模拟是近年来计算机图形学中具有挑战性的研究方向之一。OpenGL技术是实现真实感图形模拟的重要方法之一。本文使用OpenGL的编程接口,应用纹理映射技术,实现了三维场景的真实模拟。纹理映射技术的应用能增强三维场景绘制的真实感,并能提高三维场景的渲染速度。  关键词:OpenGL;纹理映射;三维场景  中图分类号:TP301文献标识码:A文章编号:1009-3044(2007)03-
期刊
摘要:介紹服装工艺设计的现状及PowerBuilder。介绍用PB+数据库实现工艺辅助设计的原理和应用。  关键词:服装工艺设计;PowerBuilder;数据库  中图分类号:TP312   文献标识码:A  文章编号:1009-3044(2006)29-0154-01
期刊
摘要:本文主要介绍利用计算机I/O接口、Microsoft Visual Basic程序、OLE面向对象设计,实现应变计的性能检测、检测路数扩展和性能检测数据可视化的功能,并根据实际应用方面的需求,对程序进行了优化设计和改進,同时探讨了应变计检测系统的精度提高方法。  关键词:应变计;性能;测试;程序。  中图分类号:TP39   文献标识码:A  文章编号:1009-3044(2006)29-0
期刊
摘要:简要的介紹了在手机游戏开发过程中常用的图形翻转方法,提出了一种采用像素点有规律重画来实现图形镜像翻转的方法,该方法能很好的解决在有限的内存空间和相对较弱的数据处理能力的情况下如何处理图形的问题,并具有很好的通用性。  关键词:J2ME;手机游戏;图形翻转;像素点  中图分类号:TP311  文献标识码:A  文章编号:1009-3044(2006)29-0160-02
期刊
摘要:办公软件中的Excel 是具有强大数据处理能力的电子表格软件,本文介绍了在高等学校中利用EXCEL的數据分析功能和函数功能来统计学生考勤情况、管理学生成绩以及进行考试质量分析的方法,使这些繁琐的管理工作变得轻松、简便。  关键词:EXCEL;教学;管理;应用  中图分类号:TP311  文献标识码:A  文章编号:1009-3044(2006)29-0166-01
期刊
摘要:本文研究提出了Windows位图文件读取显示和存盘的一种实用技术方法。特定的图像处理工作中,有时需要快捷的读取显示和存储图像数据,无必要使用代码庞大的DIB或DDB类来解决使用者的特定算法。位图文件是可视编程环境中最基本的基础图像格式,因此,文章在分析了位图的基本特点后,给出了在Win32 IDE环境下或者在Visual C++环境下实现这种要求的方法。结果表明,保存和显示方法原理清晰,易于
期刊
摘要:对Visual FoxPro多媒体编程中Multimedia MCI控件和若干API函数的使用方法进行了讨论,给出了应用示例。Multimedia MCI控件为多媒体文件的播放提供了一个标准界面。API函数中的PlaySound/sndPlaysound函数可用于小型wav文件播放。mciExecute函数、mciSengString函数可以播放多种格式音频和avi視频文件,功能更强大,可以
期刊
摘要:近年来,基于DFL[1]的agent学习已经受到了不少研究者的关注。文献[2]给出了一种即时回报的DF环境下的多agent学习模型,文献[3]给出DF环境下的单agent学习算法,文献[4]介绍了DF环境中agent的心智模型。本文主要是在这些文献的基础上,具体构建了一个基于DFL的非即时回报的合作型多agent学习模型。主要内容包括该模型的结构、主要数据结构,以及相应的算法,最后还给出了一
期刊
摘要:Photoshop CS 是一款功能强大的图像处理软件,目前已被广泛的应用于各个领域。针对Photoshop CS的初学者在学习过程中经常会碰到的一些异常现象进行介绍,并给出解决的方法。  关键词:Photoshop CS;图层;选区;灰度;栅格化  中圖分类号:TP317  文献标识码:A  文章编号:1009-3044(2006)29-0158-02
期刊