股票量化:赫兹量化国联期货极速版平台利用 DirectX 创建 3D 图形

物体建模

若要在平面空间上绘制三维物体,应首先得到 X、Y 和 Z 轴坐标上的物体模型。 这意味着物体表面上的每个点均要以特定坐标定义。 理想情况下,需要定义物体表面上的无数个点,从而在缩放图像时保持品质。 实际上,3D 建模是以多边形组成的网模来定义。 多边形端点越多,则网模越详尽,提供的模型越加真实。 然而,计算这样的模型和渲染 3D 图形需要更多的计算机资源。 早期的计算机图形不得不在较弱的图形卡上运行,故将多边形切分成三角形很久以前就出现了。 三角形可精确描述小表面部件的位置,以及计算相关参数,例如光照和光线反射。 这样的小三角形的集合能够创建逼真的物体三维图像。 在下文中,多边形和三角形将归并为同义词,因为想象三角形较之拥有 N 个顶点的多边形,显然容易得多。

按照三角形每个顶点的坐标定义来创建物体的三维模型,如此,即便物体移动或观察者的位置发生变化,也可以进一步计算物体每个点的坐标。 所以,我们要处理的是顶点,连接顶点的边线,以及由边线形成的表面。 如果知道三角形的位置,则可以利用线性代数定律来创建切面法线(法线是垂直于表面的向量)。 如此即可计算出切面如何光照,以及光线如何从切面反射。

造型

我们编写一个创建立方体的简单程序。 利用 3D 图形库中的 CCanvas3D 类。

渲染 3D 窗体的 CCanvas3DWindow 类拥有最少的成员和方法。 我们将逐步添加新方法,并针对操控 DirectX 函数中所实现的 3D 图形概念加以解释。

 
 

//+------------------------------------------------------------------+ //| 应用窗体 | //+------------------------------------------------------------------+ class CCanvas3DWindow { protected: CCanvas3D m_canvas; //--- 画布尺寸 int m_width; int m_height; //--- 立方体 CDXBox m_box; public: CCanvas3DWindow(void) {} ~CCanvas3DWindow(void) {m_box.Shutdown();} //-- 创建场景 virtual bool Create(const int width,const int height){} //--- 计算场景 void Redraw(){} //--- 响应图表事件 void OnChartChange(void) {} };

场景的创建要从创建画布开始。 然后为投影矩阵设置以下参数:

  1. 30 度视角(M_PI/6),从这处我们观看 3D 场景

  2. 纵横比(宽度与高度比率)

  3. 距剪切面近处(0.1f)到远处(100.f)的距离

这意味着仅在投影矩阵中渲染物体处于两堵虚构墙面(0.1f 和 100.f)之间的部分。 另外,物体必须落入视角的水平 30 度夹角。 请注意,距离以及计算机图形中的所有坐标都是虚构的。 重要的是距离和大小之间的相对关系,而不是绝对值。

 
 

//+------------------------------------------------------------------+ //| 创建 | //+------------------------------------------------------------------+ virtual bool Create(const int width,const int height) { //--- 保存画布维度 m_width=width; m_height=height; //--- 为渲染 3D 场景而创建画布 ResetLastError(); if(!m_canvas.CreateBitmapLabel("3D Sample_1",0,0,m_width,m_height,COLOR_FORMAT_ARGB_NORMALIZE)) { Print("Error creating canvas: ",GetLastError()); return(false); } //--- 设置投影矩阵参数-视角、纵横比、与剪裁面的近端和远端距离 m_canvas.ProjectionMatrixSet((float)M_PI/6,(float)m_width/m_height,0.1f,100.0f); //--- 创建立方体 - 将立方体的两个对角坐标、资源管理器、场景参数传递给它 if(!m_box.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),DXVector3(-1.0,-1.0,5.0),DXVector3(1.0,1.0,7.0))) { m_canvas.Destroy(); return(false); } //--- 在场景里加入立方体 m_canvas.ObjectAdd(&m_box); //--- 刷新场景 Redraw(); //--- 成功 return(true); }

创建投影矩阵后,我们可以继续构建 3D 物体 — 基于 CDXBox 类的立方体。 为了创建一个立方体,指定立方体两个对角的顶点即可。 通过在调试模式下观察立方体的创建,您可以看到 DXComputeBox() 中所发生的情况:创建立方体的所有顶点(它们的坐标已写入 “vertices” 数组),以及把立方体边线切分为三角形,列举并保存在 “indiсes” 数组当中。 立方体总共有 8 个顶点,6 个切面切分为 12 个三角形,这些三角形顶点列举为 36 个索引。

尽管立方体只有 8 个顶点,但由于要为 6 个切面中的每条法线指定单独的顶点集合,所以创建了 24 个顶点来描述它们。 法线方向会影响每个切面的光照计算。 三角形顶点在索引中的列举顺序决定了可见的三角形边线。 在 DXUtils.mqh 代码里展示了顶点和索引的填充顺序:

 
 

for(int i=20; i<24; i++) vertices[i].normal=DXVector4(0.0,-1.0,0.0,0.0);

在同一代码里为每个切面的纹理映射定义了纹理坐标:

 
 

//--- 纹理坐标 for(int i=0; i<faces; i++) { vertices[i*4+0].tcoord=DXVector2(0.0f,0.0f); vertices[i*4+1].tcoord=DXVector2(1.0f,0.0f); vertices[i*4+2].tcoord=DXVector2(1.0f,1.0f); vertices[i*4+3].tcoord=DXVector2(0.0f,1.0f); }

4 个切面顶点中的每一个都设置了 4 个角度的纹理映射。 这意味着每个立方体切面在渲染纹理时都会映射一小队结构。 当然,只在设置纹理的情况下才需要这样做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值