一种基于DirectX 9.0 API的G代码逆向渲染方法

来源:互联网 发布:linux 创建用户加入组 编辑:程序博客网 时间:2024/06/05 16:40

          

           G代码是一种工业加工描述语言,现在也广泛的运用于3D打印中。但G代码是一种单向的描述语言,很难逆向回三维模型。但近日,日本出现了一款名为MakePaintable的软件,它可以将G代码逆向回三维模型。下图所示的就是这一软件的效果图:

 

图0-1 原始三维模型

 

图0-2 逆向出的三维模型

可以看到,逆向出的模型除了与原模型形状相同,还有光照与材质。但是国内还没有这样的软件。

    另一方面,现在游戏编程中的图形渲染一般基于多边形网络(主要是三角形),绝大多数图形格式诸如STL等都是如此。G代码可以从这些三角形网络获得,但G代码却很难对游戏编程有什么帮助。

本文就提出了一种方法来逆向G代码,并且逆向出的模型包含完整形状、材质、光照、贴图等等。除了可以单纯的逆向G代码,成为一款G代码逆向器,还可以应用于游戏编程,成为一种新的图形描述办法。

该方法思路如下:


本文也就由此展开

1.G代码的解析

G代码本身只是一段文本,可以使用fstream流读入。读入之后必须将其编制成为符合要求的数据结构。

才能从中高效率的提取有关信息。G代码的语法结构与汇编语言颇有些相似,都是功能字+操作数。而一个标准的功能字又可以拆分为一个字母(比如G01的G)和一个数字(比如G01的01)。我们可以定义一个GSentence的类来表示一条完整的G指令。并用一个GProgram来表示所有G指令类GSentence的集合。在GSentence中定义一个名为GFuncition的简单数据结构来描述一条功能字:

struct GFuncition{              char Word; //字母          char Num;  //数字      };    

同时功能字后面的操作数理论上可以有无数个,所以我们必须用一个动态数组来存储它。

double *Arr;                Arr=new double[arrSize];     

其中arrSize由操作数的个数而定。

读入后首先删去注释、空格,并字母全部大写,之后通过正则表达式匹配,补齐续效指令和为0略去的参数,提取出功能字中的字母”G””M”及数字“01”“02”等。获取参数个数到arrSize并马上动态分配数字空间。下面的代码片段展示了使用正则表达式把X坐标获取到数组中:

repattren pat(“X(\d+)”)   match_results::backref_type xaxis=pat.match(Arr[1],results);  

这一切完成之后需要校错。对于三维模拟,无需考虑实际上机可能发生的操作规则错误。只需考虑代码互斥、参数缺失和语法结构错误。对于前两者,我们用一个三维数组来解决它:

GFunction GT[72][72][72];

G指令一共72条,该三维数组的第一维用来存放G指令表示,第二维用0来表示在任何情况下都不发生互斥,如果发生互斥,就把可能与其发生互斥的语句记录到这一维;第三维存放至少需要多少参数。测错时只要与这张表比对即可。部分书写错误甚至可以直接纠正。语法结构错误可以使用正则表达式匹配解决。

还有一个问题就是子程序。尽管ISO标准的G代码只支持顺序结构,但西门子、法兰克等数控研发企业已将G代码类C化,有了子程序功能。目前有两种办法处理在子程序:一种是用栈存储以供调用,另一种就是把子程序拼接回主程序。本文采用第二种。在需要执行子程序的地方读取到要调用的子程序的名称和次数、参数,直接将其替换掉。将G代码遍历完成后把子程序块删掉就可以了。这个实现不需要正则表达式,使用一段批处理脚本就可以实现,代码如下:

Set f=主程序                Set f2=需要替换的子程序     For /?>%f% If exist %f2% del %f2%                   For/f"tokens=*delims=% "%l in(%f%) do (               set line=%%l            set line=!line:FOR=F_O_R!       echo !line!>>%f2%       )          

把这段脚本保存为Replace.bat。需要注意的是这段脚本使用了命令扩展,在C++里调用时不能直接调用,必须带参数,如下所示

system("start cmd /v:on /c   Replace.bat");   

这样,一段不规则的G代码就被处理为一段规范化的G代码了。

2.G代码的编译

把G代码的数据提取完成之后,还需要编译成基于点的结构体以便下一步的绘制。

但一个代码段中必然存在模态指令,如何处理这些模态指令呢?这里我们引入了一种名为有限状态机的机制来用switch..case..模拟模态指令,一旦有模态指令触发马上跳转到对应的case进行坐标系转换、单位转换等等操作。遍历完成后跳出状态机。还需要注意的是D3D使用左手坐标系,所以还需要转换。经过这样一番处理后,所有参数变成了点的坐标,这样就可以开始使用D3D进行绘制了。


 3.使用D3D绘制出线架

在绘制之前,必须考虑插补的问题。D3D有直接画直线的函数,所以G01,G02可以灵活顶点格式定义一个FVP轻松的使用下面的代码模拟出来:

struct CUSTOMVERTEX{            float x,y,z;           }                          CUSTOMVERTEX Vertices[]=   {                              {X坐标,Y坐标,Z坐标,  偏移量,颜色}                 }            

只要把从G代码中获得的坐标信息编制成如上格式,使用DrawPrimitive方法将其渲染成线段条带(因为线段条带可以不共面)即可。

但D3D的基本图形并不包括圆弧,所以圆弧必须插补。本文使用一种简单的数据采样法进行插补,也可以使用D3D提供的三角扇形来插补,基本思路都是一样的。

一条弧线可以使用它的弦线来模拟,如图3-1.但误差从图上看来特别大。主要是因为∠α过大造成的。当∠α变小时,弧线和弦线之间将会变得非常近。圆弧插补就是这样模拟的。


4.为绘制出的图形附加纹理贴图

通过G代码生成后的物体是没有材质的,没有材质显然不能用于游戏编程,所以我们要为其附加材质。

对于一个已经绘制出线框的物体,我们需要为其附加纹理贴图。Direct3D支持多种格式的纹理贴图,比如bmp,jpg,png,tga等。同时对大小也没有绝对的限制,但为了渲染效率,我们一般使用边长为2的整数次幂的正方形图片。比如256X256、512X512等。

纹理贴图是由纹理元素组成的。纹理元素就是一个存储了颜色值的多维数组。为了将二维纹理映射到三维图形上,D3D使用了一个稍有别于(x,y)平面直角坐标系的(u,v)坐标系它的特点就是u轴向右为正方向,v轴向下为正方向。并且取值范围都是[0,1]。我们可以定义一个FVP灵活顶点格式,再使用第3步创建好的坐标数组Vertices[]的数据填充完纹理坐标后使用IDIRECT3D9TEXTURE9接口的D3DXCreateTextureFromFil-e方法创建纹理并SetTexture启用纹理即可。(D3D默认重复寻址,使用无缝衔接纹理就可以为其附加材质贴图,如图4-1)。


图4-1 使用重复寻址附加材质贴图的过程

 

5.为绘制出的图形附加光照与材质

材质与光照,这两样是紧密相连的。既然附加了材质纹理,那么光源也是必不可少的。好在DirectX提供了成熟的光源算法,可以轻松为物体添加光照。为了模拟太阳光,我们可以直接使用D3D的光源结构体D3DLIGHT9中的D3DLIGHT_DIRECTIONAL属性,即方向光源。并分别将漫反射、镜面反射和环境光颜色分别设定为0.5f,0.5f,0.5f,1.0f;1.0f,1.0f,1.0f,1.0f;0.3f,0.3f,0.3f,1.0f,衰减系数默认即可。另外,本文第4段只是附加了材质贴图,并没有附加材质,所以我们还需要使用D3DMATERIAL9结构体设置一下物体材质(物体颜色)。有一个权威公式:物体颜色总和=物体反射环境光+物体发射漫反射光+物体发射镜面发射光+自发光。所以可以使用这个公式来指定材质,就是更改结构体中五个颜色分量的值。如不赋予材质D3D将使用默认材质:反射所以漫反射光,不镜面反射,也不反射环境光,也不自发光如图5-1所示。


图5-1 平行光(方向光)照,默认材质


6.小结

    本文通过解析G代码、 编译G代码、使用D3D绘制出线架、附加纹理贴图、 附加光照与材质这几个步骤将G代码使用Direct3D应用于游戏编程中。提出了把G代码当做一种模型描述方法的思想,并做了一个简单的实现。不过要将此方法真正应用于游戏开发中的话,还有可以完善的地方,比如说附加碰撞处理等更多属性。

 

(PS:这是偶以前写的一篇论文,所以风格中规中矩,大家将就着看一下吧。网上也有人用OpenGL实现了一个跟本文差不多的系统,不过没有提出把G代码用于游戏编程,所以本文比较新的一个观点就是把数控加工中的G代码用于游戏编程。。。写的不好,献丑了。。。)



<欢迎转载,但请附带以下标志:

原标题:一种基于DirectX 9.0 API的G代码逆向渲染方法

原作者:XFRACTION

2016/2/3 发表于CSDN>

1 0
原创粉丝点击