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

管理3D图形数据

使用OpenGL渲染3D图形通常需要将若干数据集发送给OpenGL着色器管线。举个例子:想要绘制一个简单的3D对象,比如一个立方体,至少需要发送以下项目:

  1. 立方体模型的顶点;
  2. 控制立方体在3D空间中朝向表现的变换矩阵;
  3. 把数据发送给OpenGL管线。
    3.1. 通过顶点属性的缓冲区。
    3.2. 直接发送给统一变量。

关键模块介绍

渲染3D图形中需要频繁用到缓冲区、统一变量、顶点属性插值、模型-视图和透视矩阵、矩阵堆栈等关键模块。因此这一讲对这几个部分进行简单的总结。

1. 缓冲区

想要绘制一个对象,它的顶点数据需要被发送给顶点着色器。通常顶点数据会被放在一个缓冲区中,并把这个缓冲区和着色器中声明的顶点属性相关联。
OpenGL中提供了顶点缓冲对象(VBO) 和 顶点数组对象 (VAO),其中VBO就是缓冲区数组,VAO用于组织缓冲区,让缓冲区在复杂场景中更容易操控。
在应用中,我们可以声明多个缓冲区,并在各个缓冲区中绘制不同的模型。

2. 统一变量

统一变量采用“Uniform”关键字声明变量,可以让c++程序和顶点着色器进行信息交互,在渲染的过程中实现动态调整。

3. 顶点属性插值

通常我们采用顶点着色器是对单个顶点进行操作,而在光栅化的过程中我们需要对片段进行着色,于是存在插值操作。
统一变量本身不是插值的,无论有多少顶点,它始终包含相同的值。为了让结果看起来更加真实,通过缓冲区发送给顶点属性的所有值都将在管线中被进一步插值。

4. 模型-视图

这一部分即是我们第三讲中介绍的变换矩阵。通过变换矩阵对模型的位姿进行调整。

5. 矩阵堆栈

矩阵堆栈是实现多个模型变换的一种骚操作。实际上就是通过将多个模型在栈这个数据结构中push和pop,来实现有依赖的运动变换。

代码及结果

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

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

我们对每一个测试代码都输出了可视化结果,可以查看README.md文件,方便大家理解我们代码做的事情。并且代码中关键的地方,笔者都参考课本以及查阅的资料做了注释,便于理解。

drawCubeColor
drawMultipleCubes_3
drawMultipleCubesInstance_1drawPlanets_1

BUG

实际上这一讲也没什么Bug,都是小问题。

不过有些东西还是加深了理解,比如在初始化函数中,通过设置相机的位置,可以调节我们观察模型的方式和距离。比如调整深度值z,那么我们可以从更远/更近的地方来观察整个图。当屏幕中的物体较多时,通过增加z值,可以观察到更多物体。

随后是颜色缓冲区,如果在绘制动态物体时没有清除颜色缓冲区,会出现彩带,像绘制油画一样。没错,我就是梵高的弟弟——梵弟弟。

引用

[1] cg_book_practice/chapter_4

碎碎念

笔者暂时就更新到第四章过吧,因为要开始写毕业论文了,没时间看这个了。毕业要紧,后续有时间再继续更新。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值