使用MFC实现真实感图形绘制

合集下载

vc++基于mfc简单绘图

vc++基于mfc简单绘图

利用MFC简单绘图实验报告一、实验目的1、了解学会VC++ 6.0集成环境操作界面的使用;2、使用MFC进行可视化的编程;3、能够以交互方式在图形绘制区绘制点、直线、矩形、椭圆;4、设置线条的颜色、线型和线条宽度,对绘制的图元进行线条和填充属性的修改;二、简单的功能介绍1、画点:通过Ondot()函数实现2、画直线:通过OnLine()函数实现。

3、画矩形:通过OnRectangle()函数实现。

4、画圆角矩形:通过OnRoundrect()函数实现。

5、画椭圆:通过OnEllipse()函数实现。

6、铅笔工具:可以画任意线条。

通过直接在OnMouseMove(UINT nFlags, CPoint point)函数里面添加代码实现。

7、右键弹出菜单:可以在客户中点击鼠标右键,快速选择常用菜单。

通过OnContextMenu函数实现。

8、状态栏显示鼠标移动的坐标:在程序的右下角显示,通过调用setWidnowTextGetParent()实现。

9、画图颜色选择:可以画任何颜色的线条,通过OnColor()函数实现。

10、线条类型及线宽的设置:可以将画出的线条设置成实线、虚线、点线、点划线,双点划线,还可以设置线条的粗细,通过实例这一功能立刻显示所选择线条的粗细及线型。

通过新建CLineSettingDlg类,其中OnSelchangeLineStyle()函数实现线型的OnChangeEditLineWidth()函数实现线宽的改变。

再在CDrawView类中调用OnLineSetting()函数实现画笔的对话框,CLineSettingDlg类中的OnPaint()函数是实现示例功能的。

11、窗口的重绘时不擦除原来的内容:新建CShape类用来保存线条的颜色,线宽,填充色等属性,在窗口大小发生变化时有OnDraw(CDC* pDC)函数进行重绘工作,重绘中调用了各个绘图函数的Draw(CDC *pDC)函数。

第九章 使用MFC实现真实感图形绘制

第九章 使用MFC实现真实感图形绘制

第九章使用MFC实现真实感图形绘制第九章使用MFC实现真实感图形绘制真实感图形绘制是计算机图形学的一个重要组成部分。

它综合利用数学、物理学、计算机科学和其他学科知识在计算机图形设备上生成象彩色照片那样的真实感图形。

要用计算机图形设备绘制场景的真实感图形,就必须首先在计算机中建立该场景的模型,用这个模型来反映场景的特点和属性。

这一模型通常是由一批几何数据及数据之间的拓扑关系来表示的,这就是造型技术,它是真实感图形绘制技术的重要组成部分。

有了三维场景的模型,并给定了观察点和观察方向以后,就可以通过几何变换和投影变换在屏幕上显示该三维场景的二维图像。

为了使二维图像具有立体感,并尽可能逼真地显示出该物体在现实世界中被观察到的形象,就需要运用适当的光照模型,来模拟场景在现实世界中受到各种光源照射时的效果,这就是真实感图形的画面绘制技术,也就是真实感图形的生成技术。

用计算机在图形设备上生成连续色调的真实感图形大致可以分为以下四步:第一步,用数学方法建立所需三维场景的几何描述,并将它们输入至计算机。

这部分工作可由三维立体造型或曲面造型系统来完成。

场景的几何描述直接影响了图形的复杂性和图形绘制的计算耗费,因此选择合理的、有效的数据表示和输入手段是非常重要的。

第二步,将三维几何描述转换为二维投影图。

这可以通过对场景的投影变换来完成。

第三步,确定场景中的所有可见面,这需要使用隐藏面消除算法将被其他物体遮挡的不可见面消去。

第四步,计算场景中可见面的颜色,严格地说,就是根据基于光学物理的光照明模型计算可见面投射到观察者眼中的光亮度大小和色彩分量,并将它转换成适合图形设备的颜色值,从而确定投影画面上每一象素的颜色,最终生成图形。

前三步的相关知识在前面已经进行了介绍,本章将重点介绍如何通过MFC编程的方式,利用光照模型计算场景中可见面的光亮度和颜色,并绘制最终的真实感图形。

实际上,现在OpenGL和DirectX等图形函数库提供了很多支持真实感图形绘制的函数,使用它们可以更轻松的完成真实感图形绘制。

第九章 使用MFC实现真实感图形绘制

第九章 使用MFC实现真实感图形绘制
第二步,将三维几何描述转换为二维投影图。这可以通过对场景的投影变 换来完成。
第三步,确定场景中的所有可见面,这需要使用隐藏面消除算法将被其他 物体遮挡的不可见面消去。
第四步,计算场景中可见面的颜色,严格地说,就是根据基于光学物理的 光照明模型计算可见面投射到观察者眼中的光亮度大小和色彩分量,并将它转 换成适合图形设备的颜色值,从而确定投影画面上每一象素的颜色,最终生成 图形。
对全部高中资料试卷电气设备,在安装过程中以及安装结束后进行高中资料试卷调整试验;通电检查所有设备高中资料电试力卷保相护互装作置用调与试相技互术关,系电,通力根1保过据护管生高线产中敷工资设艺料技高试术中卷0资不配料仅置试可技卷以术要解是求决指,吊机对顶组电层在气配进设置行备不继进规电行范保空高护载中高与资中带料资负试料荷卷试下问卷高题总中2体2资,配料而置试且时卷可,调保需控障要试各在验类最;管大对路限设习度备题内进到来行位确调。保整在机使管组其路高在敷中正设资常过料工程试况1卷中下安,与全要过,加度并强工且看作尽护下可1都关能可于地以管缩正路小常高故工中障作资高;料中对试资于卷料继连试电接卷保管破护口坏进处范行理围整高,核中或对资者定料对值试某,卷些审弯异核扁常与度高校固中对定资图盒料纸位试,置卷编.工保写况护复进层杂行防设自腐备动跨与处接装理地置,线高尤弯中其曲资要半料避径试免标卷错高调误等试高,方中要案资求,料技编试术写5、卷交重电保底要气护。设设装管备备置线4高、调动敷中电试作设资气高,技料课中并3术试、件资且中卷管中料拒包试路调试绝含验敷试卷动线方设技作槽案技术,、以术来管及避架系免等统不多启必项动要方高式案中,;资为对料解整试决套卷高启突中动然语过停文程机电中。气高因课中此件资,中料电管试力壁卷高薄电中、气资接设料口备试不进卷严行保等调护问试装题工置,作调合并试理且技利进术用行,管过要线关求敷运电设行力技高保术中护。资装线料置缆试做敷卷到设技准原术确则指灵:导活在。。分对对线于于盒调差处试动,过保当程护不中装同高置电中高压资中回料资路试料交卷试叉技卷时术调,问试应题技采,术用作是金为指属调发隔试电板人机进员一行,变隔需压开要器处在组理事在;前发同掌生一握内线图部槽 纸故内资障,料时强、,电设需回备要路制进须造行同厂外时家部切出电断具源习高高题中中电资资源料料,试试线卷卷缆试切敷验除设报从完告而毕与采,相用要关高进技中行术资检资料查料试和,卷检并主测且要处了保理解护。现装场置设。备高中资料试卷布置情况与有关高中资料试卷电气系统接线等情况,然后根据规范与规程规定,制定设备调试高中资料试卷数,其具体含义将会在介绍 光照模型时说明。

VC++中利用MFC绘图的几种方法的探讨

VC++中利用MFC绘图的几种方法的探讨

基于OpenGL的绘图
04
方法
OpenGL简介
OpenGL(Open Graphics Library) 是一个跨语言、跨平台的专业图形编程 接口,用于渲染2D和3D图形。
OpenGL独立于窗口系统和操作系统,可以 在各种计算机平台上实现高性能的图形渲染 。
OpenGL提供了一套丰富的图形处 理功能,包括建模、变换、光照、 纹理映射等。
Direct2D绘图
适用于需要高性能绘图的场景,如游戏、多媒体应用、实时渲染等 。
方法选择建议
对于简单的图形绘制和文本输出,可以选择使用GDI 绘图。
对于需要更丰富的图形处理功能的场景,可以选择使 用GDI+绘图。
对于需要高性能绘图的场景,建议选择使用Direct2D 绘图。同时,需要注意Direct2D的使用门槛相对较高
VC++中利用MFC绘图 的几种方法的探讨
汇报人:XX 20XX-01-27
目录
• 引言 • 基于GDI+的绘图方法 • 基于Direct2D的绘图方法 • 基于OpenGL的绘图方法 • 基于自定义控件的绘图方法 • 绘图方法比较与选择
引言
01
目的和背景
探讨VC中利用MFC进行绘图的 方法和技巧,提高开发效率和绘
调用 ID2D1DeviceContext对 象的EndDraw方法结束绘 图,并检查绘图操作是否 成功。
优缺点分析
硬件加速
Direct2D利用硬件加速技术,可以 显著提高图形渲染的性能。
丰富的图形处理功能
Direct2D提供了丰富的图形处理功能 ,如变换、裁剪、透明度和图层等, 可以满足各种复杂的图形需求。
Direct2D可以与其他DirectX技术(如 Direct3D和DirectWrite)无缝集成,以实现更 复杂的图形效果。

基于MFC的简单画图程序实验

基于MFC的简单画图程序实验

简单画图程序【实验目的】本实验目的是通过构建基于MFC的windows画图程序,使学生:(1) 理解MFC应用程序的运行机制(2) 掌握使用MFC构建Windows应用程序的基本结构及编程的基本方法(3) 理解和掌握MFC应用程序消息处理机制及应用(4) 掌握类向导(ClassWizard)的使用【实验要求】(1) 必须做好实验原理的预习。

(2) 需要对提供的程序代码进行分析,并明确实验时还应在何处添加哪些语句。

【实验环境】Microsoft Windows XPMicrosoft Visual C++ 6.01 基本功能描述1) 在单文档菜单中,在菜单行中可插入一个菜单项,命名为绘图,在下拉菜单中可分别设置绘制的图形形状,如直线、矩形及椭圆,线宽选项,有1-5可供选择,还可以设置线色以及填充色,通过弹出的颜色对话框选择需要的颜色,如果不选择线宽、线色以及填充色,则按默认的画笔,画刷来绘制选择的图形。

2) 选择好图形后,通过鼠标可以绘制出相应的直线,矩形或椭圆,鼠标的按下确定图形的起点,鼠标的拖动则确定了图形的终点,即通过鼠标的拖动来决定图形的大小,当鼠标弹起,此图形则绘制完毕。

3) 增添工具栏,设置绘制的图形形状,线色以及填充色,可更方便地选择相应的功能。

2 设计思路1) 对需要用到的变量进行初始化。

2) 选择相应的图形之后就响应相应的消息处理函数,给shape赋对应的值。

选择不同的线宽,线色与填充色,即可改变画笔或画刷的属性。

3) 鼠标的按下响应函数OnLButtonDown(),捕捉鼠标当前位置得到起点的坐标,鼠标的拖动响函数OnMouseMove()改变终点的坐标,鼠标的弹起响应OnLButtonUp(),确定终点坐标,刷新,得到绘制图形。

4) 选择图形或其它属性,可进行下一次绘制。

图1 程序流程图3 软件设计3.1 设计步骤1)创建单文档创建一个MFC AppWizard[exe]工程,命名为“yinshuyan”,如图2所示,并创建单文档,如图3所示。

VC++实验四 MFC图形绘制编程实验

VC++实验四 MFC图形绘制编程实验

实验四 MFC图形绘制编程实验一、实验目的(1) 熟悉Visual C++ 6.0开发环境;(2) 掌握MFC消息映射的操作步骤;(2) 掌握MFC图形输出的方法;(3) 理解设备环境、画笔、画刷的概念,掌握常用的绘图函数。

二、实验内容请编写程序,要求如下:(1) 定义一支黄色画笔,绘制一条线段;(1) 定义一支紫色画笔,绘制一条多段线;(3) 定义一支红色画笔,绘制一个正方形,并用适当的画刷填充图形内部;(4) 定义一支绿色画笔,绘制一个圆,并用适当的画刷填充图形内部;(5) 定义一支蓝色画笔,绘制一个正六边形,并用适当的画刷填充图形内部。

三、实验报告1.列出图形绘制程序代码清单:(1)在头文件Demo.h中:#include "afxwin.h"class CDemoWnd:public CFrameWnd{public:CDemoWnd();~CDemoWnd();public:LRESULT OnPaint(WPARAM wParam,LPARAM lParam);DECLARE_MESSAGE_MAP()public:int m_nX0;int m_nY0;int m_nX1;int m_nY1;};class CDemoApp:public CWinApp{public:BOOL InitInstance();};CDemoApp ThisApp;(2)在源文件Demo.cpp中:#include "Demo.h"CDemoWnd::CDemoWnd(){m_nX0 = 0;m_nY0 = 0;m_nX1 = 0;m_nY1 = 0;}CDemoWnd::~CDemoWnd(){}BEGIN_MESSAGE_MAP(CDemoWnd,CFrameWnd)ON_MESSAGE(WM_PAINT,OnPaint)END_MESSAGE_MAP()LRESULT CDemoWnd::OnPaint(WPARAM wParam,LPARAM lParam) {CPaintDC dc(this);CPen Pen1,*pOldPen1;Pen1.CreatePen(PS_SOLID,10,RGB(255,255,0));pOldPen1=dc.SelectObject(&Pen1);dc.SelectObject(&Pen1);dc.MoveTo(10,10);dc.LineTo(100,100);CPen Pen2,*pOldPen2;Pen2.CreatePen(PS_SOLID,4,RGB(255,0,255));pOldPen2=dc.SelectObject(&Pen2);dc.SelectObject(&Pen2);POINT pt1[]={{100,10},{10,180},{200,150}};dc.Polyline(pt1,3);CPen Pen3,*pOldPen3;dc.SelectStockObject(BLACK_BRUSH);Pen3.CreatePen(PS_SOLID,4,RGB(255,0,0));pOldPen3=dc.SelectObject(&Pen3);dc.SelectObject(&Pen3);dc.Rectangle(300,50,400,150);CPen Pen4,*pOldPen4;dc.SelectStockObject(GRAY_BRUSH);Pen4.CreatePen(PS_SOLID,4,RGB(0,255,0));pOldPen4=dc.SelectObject(&Pen4);dc.SelectObject(&Pen4);dc.Ellipse(500,200,700,400);CPen Pen5,*pOldPen5;Pen5.CreatePen(PS_SOLID,4,RGB(0,0,255));pOldPen5=dc.SelectObject(&Pen5);dc.SelectStockObject(DKGRAY_BRUSH);dc.SelectObject(&Pen5);POINT pt2[]={{250,250},{400,250},{475,379},{400,509},{250,509},{175,379}};dc.Polygon(pt2,6);return 0;}BOOL CDemoApp::InitInstance(){CDemoWnd *pMainWnd = new CDemoWnd();pMainWnd->Create(NULL,"Demo Mini-MFC");pMainWnd->ShowWindow(m_nCmdShow);pMainWnd->UpdateWindow();m_pMainWnd = pMainWnd;return TRUE;}2、程序运行结果:3、总结在MFC 程序中绘制图形的基本操作步骤:(1)获取图形设备接口。

MFC实现简单画图形程序

MFC实现简单画图形程序

《MFC编程及应用》课程设计报告题目:简单画图形程序学号:姓名:指导老师:时间:程序设计步骤:一、建立基于对话框的应用程序框架;二、CMy0910200155Dlg类中关键新增变量的作用:CPtrArray pta; //用于保存已绘图形的相关信息。

CMemoryNode *pmN; //指向CMemoryNode类的指针,程序运行过程中动态保存对象信息。

CMemoryNode *pmn; //指向CMemoryNode类的指针,从文件中读取信息时动态创建类的对象。

COLORREF m_CurrentBrushColor; //用于存放当前画刷的颜色。

COLORREF m_CurrentPenColor; //用于存放当前画笔的颜色。

int num; //用于存放从"Index.txt"文件中读取的数字。

int flag=0; //用于标识:当为1时,表示按下了”画图”按钮;当为2时,表示按下了”撤消”按钮;当为3时,表示按下了”加载历史”按钮,则从文件中读取信息。

int mark; //用于标识:当为0时,表示刚画过矩形;当为1时,表示刚画过圆角矩形;当为2时,表示刚画过椭圆。

int index; //用于存放pta数组的容量。

int flag1=0; //用于标识,和flag搭配,用来处理多种情况下的窗口重绘问题。

int ButtonState=0; //用于标识,是类CShow和类CMy0910200155Dlg的一个接口,通过其值在1和0之间转换,来处理弹出式对话框的初次绘制和移动时的重绘问题。

三、CMemoryNode类中变量的作用:COLORREF BrushColor;COLORREF PenColor;int Mark; //以上三者为类CMemoryNode的成员变量,分别用来保存绘图时画刷颜色,画笔颜色和形状。

四、与控件相关联的变量:CComboBox m_BrushColor; //指示画刷颜色组合框。

VC-6.0-下MFC基于对话框-绘制图形

VC-6.0-下MFC基于对话框-绘制图形

附录表一、具体步骤:1、选择菜单栏的“新建”,选择MFC项目名为DrawGraphics,并设置为基于对话框的项目,如图-1、图-2所示;图-1图-22、按下键盘上的Ctrl+W键,调出类向导,选择“Add Class”,并点击“New”添加一个颜色按钮类CColorButton,继承自CButton类,如图-3所示:图-33、在CColorButton中添加如下成员变量:COLORREF color; //按钮颜色CPoint arrays[4]; //按钮顶点坐标BOOL IsShow; //是否显示按钮BOOL IsPressed; //按钮是否被按下4、右击CColorButton类,选择Add Virtulfunction ,重写其DraItem函数,如图-4,图-5所示:图-4图-55、为其Drawitem函数中添加如下代码:CRect rect;GetClientRect(rect);CDC dc;dc.Attach(lpDrawItemStruct->hDC);arrays[0]=CPoint(rect.left,rect.top);arrays[1]=CPoint(rect.right,rect.top);arrays[2]=CPoint(rect.right,rect.bottom);arrays[3]=CPoint(rect.left,rect.bottom);//设置背景透明dc.SetBkMode(TRANSPARENT);if (IsShow){//创建一个位图画刷CBrush brush(color);dc.SelectObject(&brush);CPen pen(PS_NULL,1,color);dc.SelectObject(&pen);dc.Rectangle(rect);if(IsPressed){CPen pen(PS_DASHDOTDOT,3,RGB(0,0,0));dc.SelectObject(&pen);dc.MoveTo(arrays[0]);for(int i=1;i<4;i++){dc.LineTo(arrays[i]);}dc.LineTo(arrays[0]);}else{CPen pen(PS_DASHDOTDOT,2,color);dc.SelectObject(&pen);dc.MoveTo(arrays[0]);for(int i=1;i<4;i++){dc.LineTo(arrays[i]);}dc.LineTo(arrays[0]);}//绘制按钮文本CString str;GetWindowText(str);dc.SetTextColor(RGB(255-GetRValue(color),255-GetGValue(color),255-GetBValue(color)));dc.DrawText(str,CRect(0,0,rect.right,rect.bottom),DT_CENTER|DT_VCENTER|DT_SINGL ELINE);}6、为CColorButton添加属性设置函数:void CColorButton::SetDrawColor(COLORREF m_color,BOOL IsShow){this->color = m_color;this->IsShow=IsShow;}7、为CColorButton添加WM_LBUTTONDOWN和WM_LBUTTONUP消息,其消息处理函数如下:void CColorButton::OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultIsPressed = true;CButton::OnLButtonDown(nFlags, point);}void CColorButton::OnLButtonUp(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultIsPressed = false;CButton::OnLButtonUp(nFlags, point);}8、为DrawGraphics项目的中的对话框资源拖拽如下控件,如图-6所示,并按表-1设置其相关ID;图-6ID 作用及类别IDC_RADIO_RECT 矩形单选按钮IDC_RADIO_ROUND 圆形单选按钮IDC_RADIO_LINE 直线单选按钮IDC_RADIO_SELF 涂鸦单选按钮IDC_RADIO_SLOIDLINE 实线单选按钮IDC_RADIO_DOTTEDLINE 虚线单选按钮IDC_COMBO_LINEVALUE 线条粗细下拉列表表-19、打开类向导,按图-7所示,为相关控件添加关联成员:10、在CDrawGraphicsDlg 类的OninitDialog 函数中添加初始化代码: BOOL CDrawGraphicsDlg:OnInitDialog() { /*.........省略无关代码...............................................................*/ // TODO: Add extra initialization hereCButton *cb; //设置相关按钮的默认选中状态 cb=(CButton *)GetDlgItem(IDC_RADIO_RECT); cb->SetCheck(1); cb=(CButton *)GetDlgItem(IDC_RADIO_SLOIDLINE); cb->SetCheck(1);IDC_STATIC_LINEEXAMPLE 显示线条粗细的Picture 控件 IDC_CHECK_BORDER 是否有边界复选框 IDC_RADIO_SOLID 填充单选按钮 IDC_RADIO_GRADIENT 渐变单选按钮 IDC_RADIO_NULL 无填充单选按钮 IDC_BUTTON_FORECOLOR 前景色按钮 IDC_BUTTON_BKCOLOR 背景色按钮 IDC_RADIO_PEN 画笔单选按钮 IDC_RADIO_CLEAR 清空画板单选按钮 IDC_STATIC_GRAPHICS 画板区(Picture 控件)cb=(CButton *)GetDlgItem(IDC_CHECK_BORDER);cb->SetCheck(1);cb=(CButton *)GetDlgItem(IDC_RADIO_SOLID);cb->SetCheck(1);cb=(CButton *)GetDlgItem(IDC_RADIO_PEN);cb->SetCheck(1);m_ComboLineValue.SetCurSel(3);m_ForeColor=RGB(255,0,0);m_BkColor=RGB(0,0,255);m_ForeCButton.SetDrawColor(m_ForeColor,TRUE); //设置前背景色按钮的颜色m_BkCButton.SetDrawColor(m_BkColor,TRUE);m_IsPressed=FALSE;m_nWidth=4;m_nPenStyle=PS_SOLID;return TRUE; // return TRUE unless you set the focus to a control}10、为CDrawGraphicsDlg添加WM_LBUTTONDOWN和WM_LBUTTONUP,WM_MOUSEMOVE消息,其消息处理函数如下:void CDrawGraphicsDlg:OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultm_IsPressed=TRUE;SetCursor(m_Hcursor);if (IsDlgButtonChecked(IDC_RADIO_SELF)){m_pOld=point;}else if (IsDlgButtonChecked(IDC_RADIO_LINE)){m_pOld=point;m_PointOrigin=point;}else if (IsDlgButtonChecked(IDC_RADIO_RECT)){m_pOld=point;m_PointOrigin=point;}else if (IsDlgButtonChecked(IDC_RADIO_ROUND)){m_pOld=point;m_PointOrigin=point;}CDialog::OnLButtonDown(nFlags, point);}void CDrawGraphicsDlg:OnLButtonUp(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultm_IsPressed=FALSE;ClipCursor(NULL); //解除鼠标的限定CClientDC dc(this);CPen pen(m_nPenStyle,m_nWidth,m_ForeColor);dc.SelectObject(&pen);if (IsDlgButtonChecked(IDC_RADIO_LINE)) //选择的为画直线{dc.SetROP2(R2_NOT); //逆转当前屏幕颜色来画线的绘图方式dc.MoveTo(m_PointOrigin);dc.LineTo(m_pOld);//擦去上一次的临时线dc.SetROP2(R2_COPYPEN);//缺省绘图模式,像素为画笔颜色dc.MoveTo(m_PointOrigin);dc.LineTo(point);//绘制固定线}else if (IsDlgButtonChecked(IDC_RADIO_RECT)) //选择的为画矩形{dc.SelectObject(GetStockObject(NULL_BRUSH));//选择空话刷dc.SetROP2(R2_NOT);CRect Oldrect(m_PointOrigin,m_pOld);dc.Rectangle(&Oldrect); //清除之前的矩形绘图dc.SetROP2(R2_COPYPEN);CBrush brush(m_BkColor);dc.SelectObject(&brush); //画这次的矩形if (IsDlgButtonChecked(IDC_RADIO_NULL)) //如果选择无填充的话,使用空画刷dc.SelectObject(GetStockObject(NULL_BRUSH));CRect Nowrect(m_PointOrigin,point);dc.Rectangle(&Nowrect);if (IsDlgButtonChecked(IDC_RADIO_GRADIENT))//如果选择渐变的话,调用渐变函数DrawGradient(dc.GetSafeHdc(),Nowrect,m_ForeColor,m_BkColor,1);}else if(IsDlgButtonChecked(IDC_RADIO_ROUND))//如果选择绘制椭圆{dc.SelectObject(GetStockObject(NULL_BRUSH));dc.SetROP2(R2_NOT);CRect Oldrect(m_PointOrigin,m_pOld);dc.Ellipse(&Oldrect);dc.SetROP2(R2_COPYPEN);CBrush brush(m_BkColor);dc.SelectObject(&brush);if (IsDlgButtonChecked(IDC_RADIO_NULL))dc.SelectObject(GetStockObject(NULL_BRUSH));CRect Nowrect(m_PointOrigin,point);if (IsDlgButtonChecked(IDC_RADIO_GRADIENT))//如果选择渐变的话,调用渐变函数DrawGradient(dc.GetSafeHdc(),Nowrect,m_ForeColor,m_BkColor,1);dc.Ellipse(&Nowrect);}InvalidateMyRect();//刷新工具区CDialog::OnLButtonUp(nFlags, point);}void CDrawGraphicsDlg:OnMouseMove(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultif (m_IsPressed&&point.x>205)//如果鼠标移动位置到达画板区{CRect rect;m_Graphics.GetClientRect(&rect);m_Graphics.ClientToScreen(&rect);ClipCursor(rect);//限定光标在指定矩形}CClientDC dc(this);if (m_IsPressed&&IsDlgButtonChecked(IDC_RADIO_SELF))//如果选择了涂鸦{CPen pen(m_nPenStyle,m_nWidth,m_ForeColor); //创建画笔dc.SelectObject(&pen); //选入画笔dc.MoveTo(m_pOld);dc.LineTo(point);//绘制轨迹m_pOld=point;//将当前点设置为旧点}else if(m_IsPressed&&IsDlgButtonChecked(IDC_RADIO_LINE))//如果选择了直线{dc.SetROP2(R2_NOT);//逆转当前屏幕颜色来画线的绘图方式dc.MoveTo(m_PointOrigin);dc.LineTo(m_pOld); //擦去上一次的线dc.MoveTo(m_PointOrigin);dc.LineTo(point);//绘制这一次的临时线m_pOld=point;}else if(m_IsPressed&&IsDlgButtonChecked(IDC_RADIO_RECT))//如果选择了矩形{dc.SetROP2(R2_NOT);CPen pen(PS_DOT,1,m_ForeColor);dc.SelectObject(&pen);dc.SelectObject(GetStockObject(HOLLOW_BRUSH));CRect Oldrect(m_PointOrigin,m_pOld);dc.Rectangle(&Oldrect);CRect Nowrect(m_PointOrigin,point);dc.Rectangle(&Nowrect);m_pOld=point;pen.DeleteObject();}else if (m_IsPressed&&IsDlgButtonChecked(IDC_RADIO_ROUND))//如果选择了圆{CClientDC dc(this);dc.SetROP2(R2_NOT);CPen pen(PS_DOT,1,m_ForeColor);dc.SelectObject(&pen);dc.SelectObject(GetStockObject(HOLLOW_BRUSH));CRect Oldrect(m_PointOrigin,m_pOld);dc.Ellipse(&Oldrect);CRect Nowrect(m_PointOrigin,point);dc.Ellipse(&Nowrect);m_pOld=point;pen.DeleteObject();}CDialog::OnMouseMove(nFlags, point);}11、为背景色、前景色、无填充、实线、虚线、边框、清空画板按钮添加按钮单击消息,响应函数如下:void CDrawGraphicsDlg:OnButtonBkcolor(){// TODO: Add your control notification handler code hereCColorDialog cdg;if (cdg.DoModal()==IDOK) //调用颜色对话框{m_BkColor=cdg.GetColor(); //更改背景色m_BkCButton.SetDrawColor(m_BkColor,TRUE);//更改背景色按钮颜色InvalidateMyRect(); //刷新工具区}}void CDrawGraphicsDlg:OnButtonForecolor(){// TODO: Add your control notification handler code hereCColorDialog cdg;if (cdg.DoModal()==IDOK){m_ForeColor=cdg.GetColor();m_ForeCButton.SetDrawColor(m_ForeColor,TRUE);InvalidateMyRect();}}void CDrawGraphicsDlg:OnRadioNull(){// TODO: Add your control notification handler code hereif (!IsDlgButtonChecked(IDC_CHECK_BORDER)) //无填充时不能也无边框{CButton *cb=(CButton *)GetDlgItem(IDC_CHECK_BORDER);cb->SetCheck(1);}}void CDrawGraphicsDlg:OnRadioSloidline(){// TODO: Add your control notification handler code hereCString str[9]={"1px","2px","3px","4px","5px","6px","8px","10px","12px"};m_ComboLineValue.ResetContent();for (int i=0;i<9;i++)m_ComboLineValue.AddString(str[i]);m_ComboLineValue.SetCurSel(3);m_nWidth=4;m_nPenStyle=PS_SOLID;InvalidateMyRect();}void CDrawGraphicsDlg:OnRadioDottedline(){// TODO: Add your control notification handler code herefor (int i=11;i>0;i--)m_ComboLineValue.DeleteString(i);m_ComboLineValue.SetCurSel(0);m_nWidth=1;m_nPenStyle=PS_DOT;InvalidateMyRect();}void CDrawGraphicsDlg:OnCheckBorder(){// TODO: Add your control notification handler code hereif (IsDlgButtonChecked(IDC_CHECK_BORDER))m_nPenStyle=PS_SOLID;else{m_nPenStyle=PS_NULL;if (IsDlgButtonChecked(IDC_RADIO_NULL)) //既不能无边框也不能无填充{CButton *cb=(CButton *)GetDlgItem(IDC_CHECK_BORDER);cb->SetCheck(1);}}}void CDrawGraphicsDlg:OnRadioClear(){// TODO: Add your control notification handler code hereInvalidate(TRUE);}12、为选择画笔宽度的下拉列表添加CBN_SELCHAGE消息,消息处理函数如下:void CDrawGraphicsDlg:OnRadioSloidline(){// TODO: Add your control notification handler code hereCString str[9]={"1px","2px","3px","4px","5px","6px","8px","10px","12px"};m_ComboLineValue.ResetContent();for (int i=0;i<9;i++)m_ComboLineValue.AddString(str[i]);m_ComboLineValue.SetCurSel(3);m_nWidth=4;m_nPenStyle=PS_SOLID;InvalidateMyRect();}13、为CDrawGraphicsDlg类添加如下的两个自定义函数InvalidateMyRect以及DrawGradient,分别用来刷新工具区和绘制渐变:void CDrawGraphicsDlg:InvalidateMyRect() //将工具区部分刷新{CRect invaRect;invaRect.top=0;invaRect.bottom=500;invaRect.left=0;invaRect.right=205;InvalidateRect(invaRect,TRUE);}void CDrawGraphicsDlg:DrawGradient(HDC pDc, const RECT &rect, COLORREF begin, COLORREF end, const int &width){RECT rcstep; //设置每次填充的矩形HBRUSH br; //创建画刷句柄int n,m;float step=0.0;int nred=0,ngreen=0,nblue=0;float red=0.0,green=0.0,blue=0.0;nred=(GetRValue(begin)-GetRValue(end));ngreen=(GetGV alue(begin)-GetGValue(end));nblue=(GetBValue(begin)-GetBValue(end));step=(float)abs(rect.top-rect.bottom)/(float)width;red=nred/(float)step;green=ngreen/(float)step;blue=nblue/(float)step;for (int start=0;start<=step;start++) //一块快绘制矩形{n=min((int)(rect.top+start*width),rect.bottom);m=min((int)(rect.top+(start+1)*width),rect.bottom);::SetRect(&rcstep,rect.left,n,rect.right+1,m);br=CreateSolidBrush(RGB(nred-red*start,ngreen-green*start,nblue-blue*start));//选择笔刷颜色HBRUSH oldbr=(HBRUSH)::SelectObject(pDc,br);FillRect(pDc,&rcstep,br);//用新颜色填充矩形区::SelectObject(pDc,oldbr);DeleteObject(br);}}二、运行结果:1、绘图效果:2、选择颜色对话框以及清空画图板功能:。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

使用MFC实现真实感图形绘制第九章使用MFC实现真实感图形绘制真实感图形绘制是计算机图形学的一个重要组成部分。

它综合利用数学、物理学、计算机科学和其他学科知识在计算机图形设备上生成象彩色照片那样的真实感图形。

要用计算机图形设备绘制场景的真实感图形,就必须首先在计算机中建立该场景的模型,用这个模型来反映场景的特点和属性。

这一模型通常是由一批几何数据及数据之间的拓扑关系来表示的,这就是造型技术,它是真实感图形绘制技术的重要组成部分。

有了三维场景的模型,并给定了观察点和观察方向以后,就可以通过几何变换和投影变换在屏幕上显示该三维场景的二维图像。

为了使二维图像具有立体感,并尽可能逼真地显示出该物体在现实世界中被观察到的形象,就需要运用适当的光照模型,来模拟场景在现实世界中受到各种光源照射时的效果,这就是真实感图形的画面绘制技术,也就是真实感图形的生成技术。

用计算机在图形设备上生成连续色调的真实感图形大致可以分为以下四步:第一步,用数学方法建立所需三维场景的几何描述,并将它们输入至计算机。

这部分工作可由三维立体造型或曲面造型系统来完成。

场景的几何描述直接影响了图形的复杂性和图形绘制的计算耗费,因此选择合理的、有效的数据表示和输入手段是非常重要的。

第二步,将三维几何描述转换为二维投影图。

这可以通过对场景的投影变换来完成。

第三步,确定场景中的所有可见面,这需要使用隐藏面消除算法将被其他物体遮挡的不可见面消去。

第四步,计算场景中可见面的颜色,严格地说,就是根据基于光学物理的光照明模型计算可见面投射到观察者眼中的光亮度大小和色彩分量,并将它转换成适合图形设备的颜色值,从而确定投影画面上每一象素的颜色,最终生成图形。

前三步的相关知识在前面已经进行了介绍,本章将重点介绍如何通过MFC编程的方式,利用光照模型计算场景中可见面的光亮度和颜色,并绘制最终的真实感图形。

实际上,现在OpenGL和DirectX等图形函数库提供了很多支持真实感图形绘制的函数,使用它们可以更轻松的完成真实感图形绘制。

本章仍采用最基本的MFC编程方式来实现真实感图形绘制,是为了让读者可以更好的体会和理解真实感图形绘制中用到的光照模型等相关知识的原理。

9.1 演示程序使用的场景造型场景造型又叫几何造型,它是在计算机中建立的用于描述现实场景的几何模型,它是真实感图形生成的一个重要部分。

在真实感图形中,一个景物的场景造型体现了该景物的几何特征和景物属性。

场景造型的复杂程度直接决定了最终绘制的真实感图形的效果。

本章的重点在于光照模型的实现,所以本章中的演示程序没有创建复杂场景,只使用了一种景物——球体。

演示程序根据球体的函数方程,计算球体表面的参数点坐标,然后按这些参数点对球体表面作三角剖分,最后利用光照模型对剖分得到的三角面片计算光照并进行绘制。

9.1.1 球体造型球体表面的函数方程式如下:x?x0?rcosucoswy?y0?rcosucoswz?z0?rsinuu?[???2,2]w?[0,?2]其中,坐标(x0,y0,z0)为球心坐标,而坐标(x,y,z)为球面上的参数点坐标,r为半径,u、w分别为纬度和经度参数变量。

我们创建一个MFC项目RealityDemo,该应用程序作为本章中的演示程序。

在该应用程序中添加一个类CObject3D,其基类为CObject。

该类的实例对应场景中的一个景物。

为了定义景物,需要定义如下结构体://三维空间中点 struct Point3D{ double x; double y; double z; };//三角面struct TriSurface{int no;//所属景物序号Point3D p1,p2,p3;//三角面的顶点 double xn,yn,zn;//三角面的法向量 }; //景物光照参数 struct Param{double krd;//景物表面红色光漫反射率 double kgd;//景物表面绿色光漫反射率 double kbd;//景物表面蓝色光漫反射率 double kra;//景物表面红色光泛光反射率 double kga;//景物表面绿色光泛光反射率 double kba;//景物表面蓝色光泛光反射率 double krs;//景物表面红色光镜面反射率 double kgs;//景物表面绿色光镜面反射率 double kbs;//景物表面蓝光镜面反射率 int n;//景物表面镜面高光指数 };Point3D定义了三维空间中的一点。

而TriSurface则定义了一个三角面片。

结构体Param中的各成员变量指定了景物的光照参数,其具体含义将会在介绍光照模型时说明。

我们在CObject3D类中添加如下的成员变量和成员函数:public://球体表面三角剖分后得到的三角面列表 CArray m_SurfaceList; Paramm_Param;//球体表面光照参数Point3D p3d[101][101];//球体表面参数点数组int countx,county;//生成的参数点在经度和纬度上的数量 doublebx,by,bz;//圆心坐标 public://创建指定球心和半径的球体void CreateBall(double x0, double y0, double z0, double r); void SetSurfaceList();//对球体表面进行三角剖分void SetFVector(TriSurface* surface);//设置三角面的法向量 void SetParam(Param param);//设置球体表面光照参数 9.1.2 生成球体表面参数点成员函数CreateBall用于生成球体表面的参数点,并按这些参数点对球体表面进行三角剖分,将剖分生成的三角面片存入到列表m_SurfaceList中,其中三角剖分由成员函数SetSurfaceList完成。

CreateBall函数的实现代码如下://创建一个球体void CObject3D::CreateBall(double x0, double y0, double z0, double r) {int i=0,j;double pi = 3.1415926; bx = x0;by = y0;bz = z0;for (double u = -pi/2;u countx = i; county = j;SetSurfaceList(); }其中u和v的步长决定了产生的球体表面的参数点的数量。

countx和county 需要在类的构造函数中设置初始值为0。

程序中将生成的球体表面参数点存入到p3d数组中,这样做是为了方便对球体表面进行三角剖分。

9.1.3 球体表面三角剖分对球体表面进行三角剖分采用如下方法。

设球体表面上一个参数点为P[i][j],则其经度上的下一个参数点为p[i+1][j],而纬度上的下一个参数点为p[i][j+1],再加上该点在对角线方向上的下一个参数点p[i+1][j+1],这四个点构成的区域可以剖分成两个三角面片。

第一个三角面片的顶点为p[i][j],p[i+1][j],p[i+1][j+1],第二个三角面片的顶点为p[i][j],p[i][j+1],p[i+1][j+1]。

在生成三角面片的同时需要计算该三角面片的法向量,因为在计算光照的时候需要用到此法向量。

平面上两个向量的叉乘积即为平面的法向量,其方向性满足右手定则,计算的时候需要注意法向量的方向应该是指向球外的。

执行三角剖分的函数SetSurfaceList和计算法向量的函数SetFVector实现代码如下://球体表面进行三角剖分void CObject3D::SetSurfaceList() {for (int i=0;ip2.x - surface->p1.x; yu = surface->p2.y - surface->p1.y; zu = surface->p2.z - surface->p1.z; xv = surface->p3.x - surface->p1.x; yv = surface->p3.y - surface->p1.y; zv = surface->p3.z - surface->p1.z;d = sqrt((yu * zv - yv * zu) * (yu * zv - yv * zu) +(zu * xv - zv * xu) * (zu * xv - zv * xu) + (xu * yv - xv * yu) * (xu * yv - xv * yu)); surface->xn = (yu * zv - yv * zu) / d; surface->yn = (zu * xv - zv * xu) / d; surface->zn = (xu * yv - xv * yu) / d; }在计算三角面片的法向量时计算的是单位法向量。

在CObject3D类中还有一个函数SetParam用于设置景物的光照参数,其实现非常简单,代码如下://设置光照参数void CObject3D::SetParam(Param param) {m_Param.kra = param.kra; m_Param.kga = param.kga; m_Param.kba = param.kba; m_Param.krd = param.krd; m_Param.kgd = param.kgd; m_Param.kbd = param.kbd; m_Param.krs = param.krs; m_Param.kgs = param.kgs;m_Param.kbs = param.kbs; m_Param.n = param.n; }我们创建景物时,首先需要实例化CObject3D对象,然后调用CreateBall函数创建球体景物,其实质是生成该球体的三角剖分面片列表,然后设置该球体的光照参数。

此时就可以使用光照模型来计算球体表面的光照并进行绘制了。

同样的,我们也可以创建其它形状的景物,其过程大体如下:获得景物表面的参数点,然后进行三角剖分,计算三角面片的法向量,最后设置景物的光照参数。

9.2 局部光照模型为了模拟光源照射在景物表面所产生的光照效果,就需要用到光照模型,光照模型是生成真实感图形的基础。

光照模型是根据光学物理的有关定律,计算景物表面上任一点投向观察者眼中的光亮度的大小和色彩组成的公式。

光照模型分为局部光照模型和整体光照模型。

局部光照模型仅考虑光源直接照射在景物表面所产生的光照效果,景物表面通常被假定为不透明,且具有均匀的反射率。

相关文档
最新文档