第三章 图形对象.docx
《第三章 图形对象.docx》由会员分享,可在线阅读,更多相关《第三章 图形对象.docx(29页珍藏版)》请在冰豆网上搜索。
第三章图形对象
第三章图形对象
即使人们不知道苹果和梨是怎么种植的,也可以吃掉它们。
那么能否不必知道构造细节,也可以绘制出复杂的图形呢?
可以,图形对象就干这种事情。
Intra3D的图形对象隐藏了几何造型与绘制的细节,用户使用简单的几个接口函数就可以绘制出图形。
Intra3D2.0版提供了三类图形对象:
(1)常用几何对象,如长方体、锥体、圆柱体、球体、圆环体、Swept形体等对象;
(2)多边形模型对象,用于绘制Autodesk公司.3ds模型和Wavefront公司的.obj模型;
(3)商业统计图形对象,如柱形图、带状图、条形图、折线图、面积图、饼图、塔形图、曲线图、曲面图、进程图、股票图等对象。
Intra3D将“图形对象”和“形体节点”(见第四章)分层设计。
图形对象负责绘制,形体节点则处理3D交互。
形体节点可以动态地引用图形对象,从而实现交互式绘制。
这种分层设计可使Intra3D核心库具有良好的可扩展性,并使交互式3D应用程序的开发更加灵活。
3.1图形对象的基类与COM接口
图形对象的基类为GraphicalObject,相应的COM接口为IGraphicalObject。
在C++类库中,几何图形对象如BoxObject、ConeObject、CylinderObject、SphereObject与TorusObject,多边形模型对象如Model3DS与ModelOBJ,商业统计图形对象如ColumnChart3D、RibbonChart3D、LineChart2D与BartChar2D等,均为GraphicalObject的派生类。
在COM库中,上述对象均继承接口IGraphicalObject。
C++类库中GraphicalObject是Container的派生类,应使用AddRef与Release函数来管理内存。
源程序见Intra3D-DLL\Include\Layer2\GraphicalObject.h。
其定义如下:
classGraphicalObject:
publicContainer
{
public:
virtualvoidDraw(void){}//图形绘制函数
//获取对象的包围盒,(dx,dy,dz)为长方体的幅值,(cx,cy,cz)为中心坐标,
virtualvoidGetBoundBox(float*dx,float*dy,float*dz,float*cx,float*cy,float*cz)
{*dx=*dy=*dz=0;*cx=*cy=*cz=0;}
//获取对象的包围球,(cx,cy,cz)为中心坐标,radius为半径
virtualvoidGetBoundSphere(float*radius,float*cx,float*cy,float*cz)
{*cx=*cy=*cz=0;*radius=0;}
//获取对象的最小坐标值(minx,miny,minz)与最大坐标值(maxx,maxy,maxz)
virtualvoidGetMinMax(float*minx,float*miny,float*minz,float*maxx,float*maxy,float*maxz)
{*minx=*miny=*minz=-0;*maxx=*maxy=*maxz=0;}
};
其中公有函数Draw、GetBoundBox、GetBoundSphere与GetMinMax均为虚函数,具体行为由派生类定义。
COM接口IGraphicalObject的定义如下(见Intra3D-COM\Intra3D.idl文件):
interfaceIGraphicalObject:
IDispatch
{
HRESULTDraw();
HRESULTGetMinMax([out]float*minX,[out]float*minY,[out]float*minZ,
[out]float*maxX,[out]float*maxY,[out]float*maxZ);
HRESULTGetBoundSphere([out]float*radius,[out]float*cx,[out]float*cy,[out]float*cz);
HRESULTGetBoundBox([out]float*dx,[out]float*dy,[out]float*dz,
[out]float*cx,[out]float*cy,[out]float*cz);
};
3.2常用几何图形对象
Intra3D2.0C++类库与COM库中的常用几何图形对象有BoxObject、ConeObject、CylinderObject、SphereObject与TorusObject。
由于这几种图形对象的设计非常相似,本节仅以SphereObject为例讲述程序设计。
程序的重点是AddRef、Release与FinalRelease的使用。
3.2.1类SphereObject的程序
C++类库中的SphereObject程序见Intra3D-DLL\Include\Layer2\SphereObject.h和Intra3D-DLL\Layer2\SphereObject.cpp。
类SphereObject的定义如下:
classSphereObject:
publicGraphicalObject
{
public:
SphereObject(void);//构造函数
voidSetSphere(floatradius,intslices=32);//设置球体参数
voidSetDrawMode(intmode);//设置绘制模式
voidSetMaterial(Material*pMat);//设置材质
voidSetTexture(Texture2D*pTex);//设置纹理
//-------------------以下为基类GraphicalObject的虚函数------------------
virtualvoidDraw(void);
virtualvoidGetMinMax(float*minX,float*minY,float*minZ,
float*maxX,float*maxY,float*maxZ);
virtualvoidGetBoundSphere(float*radius,float*cx,float*cy,float*cz);
virtualvoidGetBoundBox(float*dx,float*dy,float*dz,float*cx,float*cy,float*cz);
protected:
virtualvoidFinalRelease(void);//基类Container的虚函数
protected:
floatm_fRadius;//球体半径
intm_iSlices;//球体经纬等份数
intm_iDrawMode;//绘制模式,取SOLID或者WIRE
Material*m_pMaterial;//引用材质
Texture2D*m_pTexture;//引用纹理
};
构造函数用于初始化成员变量:
SphereObject:
:
SphereObject(void)
{
m_fRadius=1.0;
m_iSlices=32;
m_iDrawMode=SOLID;
m_pMaterial=NULL;
m_pTexture=NULL;
}
SetMaterial函数用于引用外部定义的材质对象:
voidSphereObject:
:
SetMaterial(Material*pMat)
{
//1
if(m_pMaterial!
=NULL)
m_pMaterial->Release();
//2
m_pMaterial=pMat;
//3
if(pMat!
=NULL)
m_pMaterial->AddRef();
}
SetTexture函数用于引用外部定义的纹理对象:
voidSphereObject:
:
SetTexture(Texture2D*pTex)
{
//1
if(m_pTexture!
=NULL)
m_pTexture->Release();
//2
m_pTexture=pTex;
//3
if(pTex!
=NULL)
m_pTexture->AddRef();
}
当SphereObject:
:
Release在删除自身时,应先消除对材质对象和纹理对象的引用。
此工作由SphereObject:
:
FinalRelease函数实现:
voidSphereObject:
:
FinalRelease(void)
{
if(m_pMaterial!
=NULL)
m_pMaterial->Release();
if(m_pTexture!
=NULL)
m_pTexture->Release();
}
SetSphere函数用于设置球体的参数。
SetDrawMode用于设置球体的绘制模式,绘制模式有两种,可取SOLID或WIRE模式。
voidSphereObject:
:
SetSphere(floatradius,intslices)
{
m_fRadius=radius;
m_iSlices=slices;
}
voidSphereObject:
:
SetDrawMode(intmode)
{
m_iDrawMode=mode;
}
Draw函数用于绘制球体。
当绘制模式为WIRE时,一般应将光照明关闭,否则由于光照明计算使得线框图时明时暗。
如果关闭光照明则导致材质不起作用,此时可将材质的Diffuse颜色作为线框图的颜色。
voidSphereObject:
:
Draw(void)
{
if(m_pMaterial!
=NULL)
{
//如果关闭光照明则材质不起作用,此时可将材质的Diffuse颜色作为当前颜色
floatcolor[3];
m_pMaterial->GetDiffuseColor(color);
glColor3fv(color);
m_pMaterial->Apply();
}
if(m_pTexture!
=NULL)
{
glEnable(GL_TEXTURE_2D);
m_pTexture->Apply();
}
if(m_iDrawMode==SOLID)
{
DrawSolidSphere(m_fRadius,m_iSlices);
}
elseif(m_iDrawMode==WIRE)
{
intflag;
glGetIntegerv(GL_LIGHTING,&flag);
if(flag)glDisable(GL_LIGHTING);
DrawWireSphere(m_fRadius,m_iSlices);
if(flag)glEnable(GL_LIGHTING);
}
if(m_pTexture!
=NULL)
glDisable(GL_TEXTURE_2D);
}
GetBoundBox、GetBoundSphere与GetMinMax函数的程序如下:
voidSphereObject:
:
GetBoundBox(float*dx,float*dy,float*dz,float*cx,float*cy,float*cz)
{
*cx=*cy=*cz=0;
*dx=*dy=*dz=m_fRadius*2.0f;
}
voidSphereObject:
:
GetBoundSphere(float*radius,float*cx,float*cy,float*cz)
{
*radius=m_fRadius;
*cx=*cy=*cz=0;
}
voidSphereObject:
:
GetMinMax(float*minx,float*miny,float*minz,
float*maxx,float*maxy,float*maxz)
{
*minx=*miny=*minz=-m_fRadius;
*maxx=*maxy=*maxz=m_fRadius;
}
3.2.2COM对象SphereObject的程序
COM库中的SphereObject程序见Intra3D-COM\Layer2\SphereObject.h和SphereObject.cpp。
SphereObject有两个接口:
ISphereObject与IGraphicalObject。
ISphereObject的定义如下:
interfaceISphereObject:
IDispatch
{
HRESULTSetSphere(floatradius,[defaultvalue(32)]intslices);
HRESULTSetMaterial(IMaterial*pMat);
HRESULTSetTexture(ITexture2D*pTex);
HRESULTSetDrawMode(EnumDrawModemode);
};
枚举类型EnumDrawMode定义如下:
typedefenum
{
SOLID=1,
WIRE=2,
}EnumDrawMode;
SphereObject的两个接口ISphereObject与IGraphicalObject是由类CSphereObject实现的:
classCSphereObject:
publicCComObjectRootEx,
publicCComCoClass,
publicIDispatchImpl,
publicIDispatchImpl
{
public:
CSphereObject();
DECLARE_REGISTRY_RESOURCEID(IDR_SPHEREOBJECT)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CSphereObject)
COM_INTERFACE_ENTRY(ISphereObject)
COM_INTERFACE_ENTRY2(IDispatch,ISphereObject)
COM_INTERFACE_ENTRY(IGraphicalObject)
END_COM_MAP()
public:
//-----------------------------ISphereObject接口------------------------------
STDMETHOD(SetSphere)(floatradius,/*[defaultvalue(32)]*/intslices);
STDMETHOD(SetDrawMode)(EnumDrawModemode);
STDMETHOD(SetMaterial)(IMaterial*pMat);
STDMETHOD(SetTexture)(ITexture2D*pTex);
//-----------------------------IGraphicalObject接口-------------------------------
STDMETHOD(Draw)();
STDMETHOD(GetBoundBox)(float*dx,float*dy,float*dz,float*cx,float*cy,float*cz);
STDMETHOD(GetBoundSphere)(float*radius,float*cx,float*cy,float*cz);
STDMETHOD(GetMinMax)(float*minX,float*minY,float*minZ,
float*maxX,float*maxY,float*maxZ);
virtualvoidFinalRelease(void);//类CComObjectRootEx的虚函数
protected:
floatm_fRadius;//球体半径
intm_iSlices;//球体经纬等份数
intm_iDrawMode;//绘制模式,取SOLID或者WIRE
IMaterial*m_pMaterial;//引用材质
ITexture2D*m_pTexture;//引用纹理
};
注意此处的成员变量m_pMaterial是IMaterial接口指针,m_pTexture是ITexture接口指针,FinalRelease是基类CComObjectRootEx的虚函数。
CSphereObject:
:
CSphereObject(void)
{
m_fRadius=1.0;
m_iSlices=32;
m_iDrawMode=SOLID;
m_pMaterial=NULL;
m_pTexture=NULL;
}
STDMETHODIMPCSphereObject:
:
SetMaterial(IMaterial*pMat)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if(m_pMaterial!
=NULL)
m_pMaterial->Release();
m_pMaterial=pMat;
if(pMat!
=NULL)
m_pMaterial->AddRef();
returnS_OK;
}
STDMETHODIMPCSphereObject:
:
SetTexture(ITexture2D*pTex)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if(m_pTexture!
=NULL)
m_pTexture->Release();
m_pTexture=pTex;
if(pTex!
=NULL)
m_pTexture->AddRef();
returnS_OK;
}
voidCSphereObject:
:
FinalRelease(void)
{
if(m_pMaterial!
=NULL)
m_pMaterial->Release();
if(m_pTexture!
=NULL)
m_pTexture->Release();
}
STDMETHODIMPCSphereObject:
:
SetSphere(floatradius,intslices)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
m_fRadius=radius;
m_iSlices=slices;
returnS_OK;
}
STDMETHODIMPCSphereObject:
:
SetDrawMode(EnumDrawModemode)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
m_iDrawMode=mode;
returnS_OK;
}
STDMETHODIMPCSphereObject:
:
Draw(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if(m_pMaterial!
=NULL)
{
floatcolor[3];
m_pMaterial->GetDiffuseColor(color+0,color+1,color+2);
glColor3fv(color);
m_pMaterial->Apply();
}
if(m_pTexture!
=NULL)
{
glEnable(GL_TEXTURE_2D);
m_pTexture->Apply();
}
if(m_iDrawMode==SOLID)
DrawSolidSphere(m_fRadius,m_iSlices);
elseif(m_iDrawMode==WIRE)
{
intflag;
glGetIntegerv(GL_LIGHTING,&flag);
if(flag)glDisable(GL_LIGHTING);
DrawWireSphere(m_fRadius,m_iSlices);
if(flag)glEnable(GL_LIGHTING);
}
if(m_pTexture!
=NULL)
glDisable(GL_TEXTURE_2D);
returnS_OK;
}
STDMETHODIMPCSphereObject:
:
GetMinMax(float*minX,float*minY,float*minZ,
float*maxX,float*maxY,float*maxZ)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
*minX=*minY=*minZ=-m_fRadius;
*maxX=*maxY=*maxZ=m_fRadius;
returnS_OK;
}
STDMETHODIMPCSphereObject:
:
GetBoundSphere(float*radius,float*cx,float*cy,float*cz)
{
AFX_MANAGE_STATE(AfxGetStaticModuleStat