《计算机图形学编程》笔记——第三章

数学基础

计算机图形学中大量使用了数学原理,尤其是矩阵和矩阵代数。

3D图形学中几乎每个方面、每种效果——移动、缩放、透视、纹理、光照、阴影等都在很大程度上以数学方式实现。

矩阵

图形学中大量使用了矩阵相关的操作,特别是变换矩阵、视图矩阵、模型矩阵和投影矩阵以及LookAt矩阵。

1. 变换矩阵

这里的变换矩阵指的是:平移矩阵、旋转矩阵以及缩放矩阵。尽管视图矩阵也是变换矩阵,但是为了因为它在后续会被频繁使用,于是我们给它个机会,独立介绍。
实际上,坐标系的变换可能同时包含旋转、平移和缩放,通过变换矩阵的合成功能,我们可以非常容易得到一个表示连续变换的矩阵。

2. 视图矩阵

在世界坐标系中,我们知道某个点的坐标 P w P_{w} Pw,但是在图形学中我们会构建一个虚拟相机,因此虚拟相机也有一个坐标系,我们需要在世界坐标系和虚拟相机坐标系之间进行变换,从而让虚拟相机观测到 P w P_{w} Pw 在其坐标系中的表示 P c P_{c} Pc
这个过程包含两个步骤:
a. 平移:首先将 P w P_{w} Pw 平移,其向量为负的期望相机位置。比如相机位置 C = [ C x , C y . C z ] T C = [C_{x}, C_{y}. C_{z}]^{T} C=[Cx,Cy.Cz]T,那么平移量为 t = [ − C x , − C y . − C z ] T t = [-C_{x}, -C_{y}. -C_{z}]^{T} t=[Cx,Cy.Cz]T
b. 旋转:将 KaTeX parse error: Expected '}', got 'EOF' at end of input: {P_{w} 旋转,其角度为负的期望相机旋转的欧拉角。原理如平移。

3. 投影矩阵

投影矩阵非常直观,就是将3D场景中的点投影到2D图像平面的变换。在SLAM中用得非常平凡,比如最经典的PNP算法,就是将3D点投影到2D平面构建重投影误差。而这个过程需要用到相机的内部参数,这个参数跟相机本身有关,因此图像学中需要为虚拟相机设置这些参数。
这里涉及到纵横比、视场、投影平面或近裁剪平面、远裁剪平面,即相机的结构,通过这些参数可以比较便捷地构相机参数。

4. LookAt矩阵

这个矩阵表示的是相机的摆放位置、朝向以看的方式。
简单理解:
a. 相机位置;相机摆放在哪里;
b. 看的方式:相机是正着摆放、还是反着摆放,这里需要有一个向量表示摆放的方式。比如人的头,我们通常是正着摆放的,所以提供一个垂直朝上的向量。如果我们歪头,那么向量就是侧的。
c. 朝向:即我们看向的方向。

代码及结果

这一讲中,我们将书中的代码进行整理并修改,使其适用于Linux系统。

详情可以参考代码:cg_book_practice/chapter_3/

这一讲的代码只有一个示例,就是构建了几个变换矩阵。

BUG

1. GLM

课本中提供的代码是直接采用了mat4这个数据类型,实际上笔者写出来发现没有该数据类型。于是通过多次查找发现,其包含于GLM中,需要声明glm头文件,并采用命名空间才可以使用。

glm::vec4 mPointPosition_;
glm::mat4 mProjMatrix_;

引用

[1] cg_book_practice/chapter_3/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算机图形学 VC图形编程 绘制点 绘制点 32位的COLORREF类型值来确定图形颜色值,其结构为0x00bbggrr, bb:代表蓝色值,范围从00到FF; gg:代表绿色值,范围从00到FF; rr:代表红色值,范围从00到FF; 还可以用RGB宏来完成相同的功能: RGB(short red ,short green, short blue) red 代表红色值,范围从0到255; green代表绿色值,范围从0到255; blue代表蓝色值,范围从0到255; 绘制点 void CPixelView::OnDraw(CDC* pDC) { ………… for(int i=0;i<200;i++) pDC->SetPixel(1*i,50,RGB(0,0,255)); for(int j=0;j<200;j++) pDC->SetPixel(2*j,100,(COLORREF)0x0000ff00); for(int m=0;m<200;m++) pDC->SetPixel(3*m,150,(COLORREF)0x000000ff); for(int n=0;n<200;n++) pDC->SetPixel(4*n,200,(COLORREF)0x0000ffff); for(int p=0;p<200;p++) pDC->SetPixel(5*p,250,(COLORREF)0x00ff00ff); for(int s=0;s<200;s++) pDC->SetPixel(6*s,300,(COLORREF)0x00000000); } 使用鼠标绘图 在VC中,鼠标的各种事件(单击鼠标左键,单击鼠标右键,双击鼠标左键,双击鼠标右键,移动鼠标)被作为消息,通过系统自带的消息映射功能,对操作者的不同操作进行响应处理。 使用鼠标绘图 绘制直线 void CCreateLineView::OnLButtonDown(UINT nFlags, CPoint point) { CDC* pDC=GetDC();//获取设备环境 pDC->SelectStockObject(NULL_BRUSH);//空画刷,选取库存的GDI模式 使用鼠标绘图 绘制直线 switch(m_step) { case 0://当第一次单击鼠标左键 m_Startp=m_Endp=point;//确定直线的起点 m_step++;//等待输入直线的终点 break; 使用鼠标绘图 绘制直线 case 1://当第二次单击鼠标左键 m_Endp=point;//确定直线的终点 m_step=-1;//使得再单击鼠标左键均无效 //m_bline=TRUE;//生成直线 DrawLine(pDC,m_Startp,m_Endp);//绘制直线 break; default://为空操作,表示不再绘制新直线; } 使用鼠标绘图 绘制直线 ReleaseDC(pDC);//释放不再使用的DC CView::OnLButtonDown(nFlags, point); } 使用鼠标绘图 绘制直线 void CCreateLineView::DrawLine(CDC *pDC, CPoint start, CPoint end) { pDC->MoveTo(start.x,start.y); pDC->LineTo(end.x,end.y); } 使用鼠标绘图 绘制直线 设置4个成员变量 使用鼠标绘图 绘制直线 设置橡皮筋模式 void CCreateLineView::OnMouseMove(UINT nFlags, CPoint point) { CDC* pDC=GetDC(); int nDrawmode=pDC->SetROP2(R2_NOT);//设置绘图模式:屏幕颜色反色。 pDC->SelectStockObject(NULL_BRUSH); 使用鼠标绘图 绘制直线 设置橡皮筋模式 if(m_step==1&&!m_bline) { CPoint prePnt,curPnt; prePnt=m_Endp;//获得光标所在的前一个位置 curPnt=point; 使用鼠标绘图 绘制直线 设置橡皮筋模式 DrawLine(pDC,m_Startp,prePnt);//绘制橡皮线 DrawLine(pDC,m_Startp,curPnt); m_Endp=point; } pDC->SetROP2(nDrawmode);//恢复先前的绘图模式 ReleaseDC(pDC);//释放DC 与绘图相关的GDI对象类 CBitmap类,CBrush类,CFont类,CPen类 CRgn类,CPalette类。 通常,我们都是使用GDI绘图对象类所创建的对象进行绘制各种图形的, 好象画家手里的画笔,而设备环境就是用什么样的画纸。 CPen 画笔是一种用来画线及绘制有形边框的工具,用户可以指定它的颜色及厚度,并且可以指定它画实线、点线或虚线。 CPen(int nPenStyle,int nWidth,COLORREF crcolor); CPen CPen(int nPenStyle,int nWidth,COLORREF crcolor); nPenStyle: PS_SOLID:实线画笔。 PS_DASH:虚线画笔。 PS_DOT:点线画笔。 PS_DASHDOT:点划线画笔。 CPen CPen(int nPenStyle,int nWidth,COLORREF crcolor); nWidth :指定画笔宽度。 CPen for (int i=0;i<7;i++) { CPen NewPen1(PS_SOLID+i,1,RGB(0,255,0)); CPen *pOldPen=pDC->SelectObject(&NewPen1); pDC->MoveTo(10,20*i+10); pDC->LineTo(700,20*i+10); pDC->SelectObject(pOldPen); } CBrush 画刷定义了一种位图形式的像素,利用它可以对域内部填充颜色。 CBrush(int nIndex,COLORREF crcolor); CBrush CBrush(int nIndex,COLORREF crcolor): nIndex:画刷的阴影线的风格 HS_BDIAGONAL:从左到右向下成45度的对角线。 HS_CROSS:水平线和垂直线相交的十字交叉线。 HS_DIAGCROSS:夹角为45度的斜十字交叉线。 HS_FDIAGONAL:从左到右向上成45度的对角线。 HS_HORIZONAL:水平阴影线。 HS_VERTICAL: 垂直阴影线。 CBrush CBrush NewBrush1(RGB(0,255,0)); CBrush *pOldBrush1=pDC->SelectObject(&NewBrush1); pDC->Rectangle(50,50,200,300); pDC->SelectObject(pOldBrush1); CBrush CBrush NewBrush2(HS_BDIAGONAL,RGB(255,0,0)); CBrush *pOldBrush2=pDC->SelectObject(&NewBrush2); pDC->Rectangle(250,50,400,300); pDC->SelectObject(pOldBrush2); CFont 字体是一种具有某种风格和尺寸的所有字符的完整集合,它常常被当作资源存于磁盘中,其中有一些还依赖于某种设备。 扫描转换矩形 void CFillView::Fillrectangle(CDC *pDC, COLORREF rccolor) { int x,y; for (y=50;y<300;y++) for (x=50;x<200;x++) { pDC->SetPixel(x,y,rccolor); } } 扫描转换矩形 void CFillView::OnLButtonDown(UINT nFlags, CPoint point) { if ((50 < point.x) & (point.x <200) & (50<point.y) & (point.y<300)) {CDC *pDC=GetDC(); Fillrectangle(pDC, RGB(255,255,0)); } CView::OnLButtonDown(nFlags, point); } 谢 谢

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值