张泷

来自CGTWiki
跳转至:导航搜索
张泷

个人简历

生于1994年5月25日,籍贯河南。

2019级  北京邮电大学  信息光子学与光通信研究院  电子与通信工程  硕士研究生

四级:451

主要研究方向为三维显示和计算机图形学。

Tel: 18003770732
Email: 641261684@qq.com

电脑配置

操作系统 Windows 10 专业版 64位 ( 4.09.00.0904 )
	
处理器	英特尔 Core i9-9900K @ 3.60GHz 八核

主板	技嘉 Z390 AORUS ULTRA-CF ( 英特尔 PCI 标准主机 CPU 桥 - Z390 芯片组 )

内存	32 GB ( 金士顿 DDR4 3200MHz )

主硬盘	三星 MZVLB256HAHQ-00000 ( 256 GB / 固态硬盘 )

显卡	Nvidia GeForce RTX 2080 ( 8 GB / 技嘉 )

显示器	三星 SAM0C1A S24E390 ( 23.5 英寸  )

声卡	英特尔 High Definition Audio 控制器

网卡	英特尔 Wireless-AC 9462

无学校标示版本

ftp://cgt3d.cn/%C6%BD%CC%A8%CF%E0%B9%D8/%C6%BD%CC%A8%B0%B2%D7%B0%B0%FC/%CE%DE%D1%A7%D0%A3%B1%EA%CA%B6%B0%E6%B1%BE/

目前的工作

  • 615
  1. 目前udp传输的还是经纬度等信息,后面的动画的调用,模型的加载还要考虑如何传递。
  2. 光场参数已经调好,基本可以正确展示场景。

cef

  1. cef最终要作为UI在OSG中展示,那么就可能会覆盖掉原本的鼠标事件,需要想下怎么解决。

早会

  • 2021/9/9
  1. 明确后面优先尽快在光场上正确显示地球
  • 2021/9/8
  1. 测试光场部分代码,修复光场显示bug
  • 2021/9/7
  1. 继续标注和飞机动画的同步,然后找时间先测试光场下分辨率是否合适。
  • 2021/9/6
  1. 开始写标注同步,飞机动画的同步
  • 2021/8/25
  1. 前面ce看的比较少,开始看一些CE的东西。
  • 2021/8/24
  1. 改615的UDP接收部分代码的BUG
  • 2021/8/23
  1. 基本完成615的UDP接收部分代码
  • 2021/8/23
  1. 写615的UDP接收代码
  • 2021/8/20
  1. 优先解决打包OSG光场代码遇到的问题,然后看看ce。
  • 2021/8/19
  1. 继续615的udp接收部分的工作
  2. 打包OSG中的光场代码

周报

  • 2021/8/5(周四)

615的udp传输存在的问题:

1.将之前的c++的udp代码改为clr的形式,但是传输存在错误,正在改。

2.clr中采用了.net的序列化,但是序列化后的长度较长,会有超过1500字节的情况,可能会影响传输。


  • 2021/7/19(周一)

615项目:之前写的UDP传输demo中涉及到的网络库,以及部分c++写法,在平台的CLR模式下不支持,需要重写。

  • 2021/6/10(周四)

解决readnode的回调函数中无法区别倾斜摄影与其他模型的问题

解决在OSGEarth中用缓存机制加载本地模型存在白模的问题

经过测试,可以不依赖boost的dll正常运行

  • 2021/5/20(周四)

已完成:

化工园区的模型的加载和显示隐藏。

模型高亮的测试。

下一步:

解决curl下载文件不完整。

看earth关于缓存的源码。

线程池的使用。

  • 2021/4/9(周四)

完成cef与OSG结合的demo。

  • 2021/4/9(周五)

cef嵌入OSG中无法读取buffer的问题,确定是由于线程冲突导致的。

目前准备参照GitHub上的例子,在现有的cef库基础上加上线程锁再测试。

  • 2021/4/2(周日)

1.在网页端加载倾斜摄影后,第二次打开会出现部分倾斜摄影无法加载的问题。

进一步检查后发现是数据在被缓存到本地时,

出现了部分数据丢失的问题,导致倾斜摄影无法加载。

下一步使用另一套倾斜摄影数据测试,若问题依旧则准备重写缓存部分的代码。

2.cef与OSG的结合:存在的问题是cef的onPaint()中的参数buffer,无法正确读取至osg中。报的错误为内存读取错误。

  • 2021/3/13(周日)

郑伟泽找到了一个老版本的水狐,可以使用64位的npapi了。

给光场显示器用的unity程序添加了参数保存的功能。

  • 2021/2/28(周日)

npapi能在32位下编译成功,无法在64中编译。但是目前用的osg都是在64位下编译运行的,如果要在32位的npapi中调用osg的dll,就无法编译。

  • 2021/1/30(周六)

新增单屏幕下不打开双屏OSG。

  • 2021/1/24(周日)

完成OSG双屏的适配。

  • 2021/1/13(周五)

实现退出时第二屏幕的关闭,但是平台仍无法正常退出(在debug下)。检查后发现是615的分支存在无法彻底退出的问题。

  • 2021/1/8(周五)

尝试通过使用第三方库LibGizmo在平台中加入拖拽器,由于LibGizmo只有32位版本。所以先对源码进行修改,编译出了64位版本。下一步将测试用例调通,然后尝试在平台中加入拖拽器。

  • 2020/11/12(周日)

新增平台中gps数据的获取。

新增根据gps修改模型位置。

与装甲兵联调模型的移动。

  • 2020/09/06(周日)

修改名空间与项目名不一致的文件。

修改float3d全屏,但是还存在位置不正确的问题。

float3d
  • 202/08/30(周日)

使用float3D覆盖全屏后的地球窗口,然后将float3D窗口置顶,但是无法显示textblock控件,但是能够显示textbox控件 ,所以可以将textbox控件透明,实现经纬度的显示。

  • 202/08/22(周六)

修复平台中的BUG:对路径进行“修改视点信息”时,直接点击“删除”不会报错,但先点击“视点1”,再点击“删除”,平台崩溃

录制保存机制的视频并上传wiki

  • 202/08/14(周五)

修复osg中拼接视频无法在小窗口恢复播放的问题。
作一个保存机制的ppt。

  • 202/07/19(周日)

修改视频模型的保存方式。

  • 202/07/05(周日)

完成矢量图层保存加载删除

  • 202/06/27(周六)

完成路径列表和视点列表的数据绑定

  • 202/06/21(周日)

完成国界线的加载

  • 202/06/06(周日)

完成各个漫游路径中视点列表展示,增加修改视点信息修改。

  • 202/05/31(周日)

完成一个Treeview绑定后台数据的demo,尝试往平台中移,如果难度大的话就还按旧代码写。

  • 202/05/23(周六)

完成视点和路径的重名,尝试修改并运行论文里的着色器代码,运行后只有左侧的模型。

  • 202/05/17(周日)

添加视点的xml保存,完成一个利用Windows API :sendmessage实现进程间收发消息的例子。

  • 202/05/10(周日)

修复视点,漫游的bug,重写漫游的xml读写。修改场景树xml代码中存在的问题。

  • 202/05/01(周日)
  1. 阅读了【建筑信息模型(BIM)的高效立体渲染】这篇论文,准备复现论文中的两个方法。现在的问题是如何使用文中的两个着色器代码还是没有什么头绪。
  2. 阅读了osgearth中的videolayer源码。
    VideoLayerOptions opt;
	opt.url() = fileName;
	VideoLayer* layer = new VideoLayer(opt);
	map->addLayer(layer);
  • 目前还不是不能实现油管的展示视频中的效果。首先,videolayer的使用需要向的构造函数传递一个videolayerOptions的对象,这个videolayerOptions类的顶层基类是ConfigOptions

主要是用来操作Config这个类。但是目前还没搞明白config有什么用处。所以示例中向VideoLayerOptions传递的文件名还不清楚是什么文件,尝试视频文件或者网络流媒体都无效,会报文件无法读取。 当传给一个jpg文件时候可以看到地球表面是有图像的,所以可能还传递文件的方式有问题。

文件:2020-5-1图.png



  • 202/04/12(周日)
修改了场景树获取播放器的方式
  • 202/04/12(周日)

1.解决在场景树无法获取当前播放器控件的问题,编写场景树中视频部分的右键菜单功能,增加右键菜单中的视频播放,删除,停止。

完成了平台中视频模型的保存和再现功能。

2.学习learnOpenGL教程。

  • 202/04/06(周一)

1.添加场景树右键加载模型,右键删除模型写完了,还未上传。
2.平台会出现无法启动的BUG,还在找原因。

  • 202/03/29(周日)

1.平台补充了删除右键视频的功能(还未上传)。
2.本周主要在看osg的渲染视频(但是没太明白。。。有点抽象。。。),还有最长一帧。


  • 202/03/20(周五)

1.本周没有大的进展,场景树右键播放的功能暂时放下来。

2.邢师兄之前分享的海康威视结合OpenCV播放实时视频问题。目前通过阅读分享的代码,例子中海康威视部分还是采用开发文档中预览实时码流的第二种方式,即通过回调函数获取
海康的码流(yv12),然后将yv12转为yuv提供给OpenCV使用。问题是不管是yv12还是yuv,目前我找不到在osg中使用这两种格式的方式。

3.对于osg的纹理贴图,现在平台上的将视频加载到模型上的功能就是以纹理的形式贴在一个矩形上。然后还有一种方式就是将纹理动态的更新出来,形成视频。但是这种方式很低效,
我通过osg自带示例测试了这种方式,使用的是一段60帧1080p的视频,将是视频的每一帧加载进去,流畅性没问题,但是加载很慢,而且很吃内存,一段600帧的素材,启动后吃掉了3.8G的内存

4.邢师兄之前提供的两个rtsp视频流,我这边测试了一下,用vlc播放是可以的,但是通过FFME播放的话会卡在第一帧,目前还不清楚问题在哪。

5.这周osg学习看的比较少。

  • 2020/03/15(周日)

1.在平台上实现了视频路径的保存,启动后添加至场景树。模型的路径保存至xml文件的功能也准备好了,但是还没有添加保存至场景树的功能。这次把对xml的操作都写在一个类里面,
后续如果有其他的读写xml的功能,准备还在这个类的基础上增加功能。

2.原来计划添加右键场景树的菜单,选择播放,然后在下方窗口播放视频。右键菜单没问题,问题是在平台里获取播放控件都是通过一个IApplication类的对象,即Iapplication.GetSceneTreeGrid(),
在场景树部分的代码里目前无法获取还获取平台启动时创建的Iapplication对象。如果不能获取的话需要改回原来的点击按钮,弹出对话框,播放视频的路子。

3.继续学习最长一帧,然后加上一些osg的视频(B站的)。


  • 2020/03/08(周日)

1.目前平台里的ffme.windows插件可以直接播放rtmp,http视频流,rtsp理论上也可以直接放(没有找到rtsp视频源,暂时无法测试),在osgearth中也可以直接播放,但是观感上有卡顿,
cpu占用并不高,也可能是网络问题。

2.着手开始解决平台的视频模型保存功能。目前已经在自己的测试用例中完成了xml增删查的功能,接下来要移入平台,实现开启平台后直接读取xml文件,并创建对应的TreeView。目前的想法是
不直接播放视频,而是先将视频地址等信息存入Treeview,然后在右键菜单中添加播放功能。模型的载入也参考这种方式,准备先把视频的完成,再去修改模型载入的部分。

3.上次最长一帧是看到第三日,没太懂,所以又从开头开始看,感觉这次容易理解了。文章中的源码还是跟现在版本相比还是有变化的,思路没有变,但是调用方式有变化。结合源码看还是比较直观的。


  • 2020/03/01(周日)

文件:2020.02.29.docx

1.按照海康威视的sdk中的使用方法,是将窗口的句柄交给sdk去播放,或者只取视频流,然后调用海康威视的播放库来预览视频。

由于平台使用的是wpf平台,不方便获取控件的句柄,需要在grid控件里面嵌入winform的picturebox控件,再获取picturebox的句柄,交由sdk。

这样子就不适合当前所用的方式,即在平台里面使用ffmpeg播放视频。这样子话,也就不能播放本地视频了。

2.关于用ffmpeg播放。调用ffmpeg大多是再c或c++下使用的,关于c#使用的很少。
但是,网上转了一圈后发现c#中有一个ffmpeg.Auogen项目,里面基本涵盖了ffmpeg的大部分接口,可以用nuget包管理器直接导入,直接调ffmpeg解码。
具体后续我再找资料看看。

3.继续观看了c++和图形学的视频


  • 2020/2/21(周五)

文件:2020.02.21.docx
1.在看海康威视开发文档里的demo,里面主要是用三种方式写的c++,c#和Java。C++用的是mfc库开发的,我查了下,这个用的不多了。
所以就可以参考c#的例子去做。

2.结合osg的源码在看最长的一帧的前三日的内容。有一点难度。

3.海康威视的用c#开发的demo里,比较陌生的还是Windows下开发的一些写法,不过c#的源码相较于c++的还是相对好理解一些。

4.下一步的话还是最长一帧和海康的开发文档交替看。


笔记

光栅化

参考链接:https://www.jianshu.com/p/54fe91a946e2?open_source=weibo_search

计算机的屏幕可以看做为一个二维坐标系,以左下或者左上为原点。

屏幕坐标系
  • 将三维模型投在二维屏幕上显示,需要经过一下几步:
  1. 坐标变换
  • 模型的顶点坐标通过MVP(Model-View-Projection)变换后再经过归一化得到设备坐标。
最后按照显示设备的宽高通过视口变换得到设配显示设备的坐标。
  1. 颜色计算
  • 计算每个顶点的颜色,通过UV贴图的颜色,结合光照,透明度等,计算出模型每个顶点的具体颜色(R, G, B)。
  1. 光栅化
  • 假定屏幕分辨率为1920×1080,在二维屏幕渲染(光栅化)时,内存中frame buffer只保存着1920×1080个屏幕点的颜色,
然后一个一个的画到屏幕上。(它的实现方式是以一个1920×1080长的一维数组储存每个顶点的RGB颜色,然后遍历数组画出来)
什么X, Y, Z,什么alpha之类的frame buffer都没有的,在frame buffer里只有3个值:R, G, B。X, Y, Z, alpha等等属性要在另外的地方存储。

光栅化,就是计算出1920×1080这么长的RGB数组中,每一个RGB的值。

  • 1920×1080的屏幕只有1920×1080=2073600个像素点。所以光栅化的连点描边是一个近似过程。
也就是说只能用形状近似的像素点去描述一个面片。

光栅化主要有以下几步:

  1. 读取模型的顶点,3个3个的读,因为要画三角形。
  2. 将3个顶点两两连成线,形成三角形。
  3. 计算屏幕像素点在三角形内还是三角形外。在三角形内部的,就上色(颜色是之前算出来的),在三角形外部的,就不上色。
    (注意:如果一个三角形挡在另一个三角形前面,我们应该只画前面的三角形。所以这里还需要比较一下正准备上色的这个像素点是不是已经上过色了。
    如果这个像素点已经上过色了,并且它是被Z=1的顶点上的色,而我们正准备上色的这个顶点的Z=2(说明这个顶点被挡在了后面),那么这个顶点就不应该上色,因为它是被挡住的点。)
  4. 不断的循环,直到画完3D模型的所有三角形,这样一个模型就出来了!
光栅化中的三角形
  • 由此带来一个问题:如何确定一个像素点是否在三角形内部?
  1. 首先判断像素是否在三角形内,以像素的中心为准
  2. 以下图为例,对于点F和向量DF而言,如何判断F点在DE的左边还是右边:将点F和点D组成向量DF,将向量DF和向量DE叉乘,根据右手法则,可以得到一个
    方向向上的,垂直于DF和DE的向量。在以向上(即朝屏幕外侧)为正情况下,可以说点F在向量DE的左侧。反之,若F在DE的右侧,可以得到一个负的向量。
  3. 由此,若一个点在三角形内部,那么将三角形的三个点A,B,C以顺时针(逆时针)连城三个向量,然后判断点P是否均在三个向量的左侧(右侧),即可得出
    点P是否在三角形内部。
点和三角形.png

反走样(抗锯齿)

参考链接:https://www.cnblogs.com/cnblog-wuran/p/9769321.html

  • 锯齿”是“走样”(aliasing)的一种形式。而走样是光 栅显示的一种固有性质。产生走样现象的原因是像素本质上的离散性

走样现象:

  • 光栅图产生的阶梯型(锯齿形)
走样.png
  • 图形中包含相对微小的物体时, 这些物体在静态图形中容易被丢弃或忽略
走样1
  • 小物体由于“走样”而消失,在动画序列中时隐时现,产生闪烁。
矩形从左向右移动,当其覆盖某些像素中心时,矩形被显示 出来,当没有覆盖像素中心时,矩形不被显示
走样2

如果对一个快速变化的信号采样频率过低,所得 样本表示的会是低频变化的信号:原始信号的频率看起来被 较低的“走样”频率所代替.

采样频率低

反走样技术

  • 用于减少或消除走样效果的技术,称为反走样(Antialiasing)技术

1.提高分辨率

采用分辨率更高的显示设备,对解决走样现象有所帮助, 因为可以使锯齿相对物体会更小一些

2.模糊边界

反走样技术涉及到某种形式的“模糊”来产生更平滑的图像

对于在白色背景中的黑色矩形,通过在矩形的边界附近掺入 一些灰色像素,可以柔化从黑到白的尖锐变化

从远处观察这幅图像时,人眼能够把这些缓和变化的暗影融 合在一起,从而看到了更加平滑的边界

反走样模糊边界.png

反走样方法

  • MSAA(MultiSampling Anti-Aliasing)
将一个像素划分成多个像素,然后判断这多个像素都有哪些在三角形内,然后金四处三角形在此原始像素中所占比例,
接着取平均值,计算此原始像素应当的颜色,最后再做正常的采样。
Supersampling.png

FXAA(Fast Approximate Anti-Aliasing)

快速近似抗锯齿,是通过得到一幅有抗锯齿的画面,然后找到边界,将锯齿边界替换成没有锯齿的边界,这是一种在图像层面做处理的操作,速度较快。

着色,漫反射

参考链接:https://zhuanlan.zhihu.com/p/136945620

https://www.pianshen.com/article/30291103659/

可见性问题

  • Z-Buffer算法

Z-Buffer记录每个像素的两个缓存值,一个是深度缓存,一个是颜色信息。


其中像素点的深度缓存是该像素所对应的3D物体的最小的Z轴坐标值。Z-Buffer算法不做排序。

Z-Buffer示例

上图中,R代表无穷大,数值代表Z轴坐标值。

  • Z-Buffer伪代码
Initialize depth buffer to ∞
During rasterization:
 for (each triangle T)
  for (each sample (x,y,z) in T)
   if (z < zbuffer[x,y])  // closest sample so far
    framebuffer[x,y] = rgb; // update color
    zbuffer[x,y] = z;   // update depth
   else
    ;  // do nothing, this sample is occluded

Z-Buffer的复杂度是[math]O\left ( n \right )[/math],注意这里只是找到最小值即可,所以只需遍历所有像素点。

  • 着色(shading)

Blinn-Phong 光照模型

Blinn-Phong Reflectance Model (BPRM) 是一个比较简单的着色模型。

Shading1.png

Specular highlights:镜面高光,即当光打在一个表面光滑的物体上时,就会产生镜面反射。


Diffuse reflection:漫反射。


Ambient lighting:环境光。我们知道人之所以看得见物体是因为物体把光反射到了我们的眼睛。


那为什么我们能看到最下面的那个绿色杯子的背面呢?按理说右上角的光应该照不到那块啊。


我们之所以能看到,其实就是因为环境光的原因,简单理解就是,


右上角的光源打在墙上,然后通过漫反射又把光打在了桌子和绿色杯子的背面,所以我们就看得见了。简单理解环境光就是二次光。

反射

反射

观测方向(view direction):着色点到相机的方向,即[math]\overrightarrow{v}[/math] 表面法向(surface normal):垂直着色点的反向,即[math]\overrightarrow{n}[/math] 光的方向(light direction):着色点到光源的方向,即[math]\overrightarrow{l}[/math]


注意起点也是着色点,而不是光源,这是一种约定俗成的规定,也是对编程模型的预约定,这样可以不引入光源数据结构,只从着色点出发做处理,这样会简便很多。


表面参数(surface parameters): color,shininess(比如光的亮度)


漫反射


对于漫反射,首先要考虑接收到的光强的损失。


假设下左图表面是一个边长为1的正方形,那么此时由于光线垂直该表面,


所以单位面积接收到的能量是最多的,而旋转一定角度后,


很显然单位面积接收到的光线能量就变小了,所以对应地,旋转后的表面的亮度就会暗一些。


所以,应该将光强乘上一个[math]cos\Theta[/math]

兰贝特余弦定律

光衰减原理 假设光在传播过程中没有能量损失,那么以光源为球心的整个球面所接收的能量为E。

假设球面的半径为r,对于球面上某一个点的[math] E=4\pi \times 1^{2}\times I=4\pi I [/math].

那么对于球面上的某一个点,该点的能量为[math]E/(4\pi r^{2})=I/r^{2} [/math]。由此可知虽然

所有球面的能量是相等的,但是每个店的能量却是衰减的。即light falloff。

光衰减.png

结合前面提到的Lamber's cosine law和light falloff,我们可以知道每个着色点的光亮程度计算

[math]L_{d}=k_{d}(I/r^{2})max(0,\overrightarrow{n}\cdot \overrightarrow{l}) [/math]

[math] k_{d} [/math]是指漫反射系数,代表颜色信息。如果[math] k_{d} [/math]是一个标量,

那就应该表示明暗(黑白)程度,如果是一个三通道的向量,那么就可以表示具体的颜色了。

[math] max(0,\overrightarrow{n}\cdot \overrightarrow{l}) [/math],这里为什么要取最大值?

是因为单位面积接收到光的能量和 法向和光线夹角 有关。而我们一般认为如果夹角的绝对值大于90度

则没有意义。

着色管线

参考链接:https://zhuanlan.zhihu.com/p/143658280


  • 高光项

当我们去看一面镜子的时候,当我们的视线越接近光线的镜面反射方向,就越容易看到高光(就是镜子的反光)。 以下图为例,当我们的观察方向V越接近反射方向R,高光就越明显。

高光.png

上面提到了判断高光的方法就是看V和R是否接近,越接近则高光越明显。 但是实际中这种计算方式并不好计算,所以blinn-Phong模型对此进行了改进。

Blinn-Phong高光.png

首先定义了一个新的向量h。叫做半程向量。表示的是光线的入射方向l和观测方向v之间的中间向量。

那么当V接近R的时候,h一定会接近法线n。所以问题就变成了判断n和h是否相近。

上图中的Ls是镜面反射公式。

Ks表示反射系数,可以理解为颜色,即白色。

同时这个公式的最后一项是P次方。而之前的漫反射公式并没有次方。

这是因为实际中能观测到高光的角度其实非常小,而cosin函数(如下图)的衰减(0到90度)较为缓慢,因此需要

为其加一个次方,来使其快速衰减,从而减少高光的范围。

Cosin.png
  • 环境光

环境光是由其他类型的光或者漫反射的光反射过来产生的,一般假设环境光强度都相同,为Ia。

环境光计算公式为:

[math] L_{a} = k_{a}I_{a} [/math]

  • 总的反射效果

漫反射,镜面反射,环境光,三者总的反射计算公式:

Blinn-Phong反射模型公式.png
  • 着色频率
平面着色1.png

平面着色(Flat shading)

一般默认是对一个三角形着色,根据上面提到的着色公式,我们首先要计算出三角形的法线,然后结合h和l直接套公式即可。

对应上图中最左边的球。

Gourand Shading

该着色方法的改进在于先求出每个三角形三个顶点的法向量,之后通过差值对三角形内部进行着色。 对应上图中第二个球。

Phong Shading

PhongShading的思路是先求出三角形三个顶点的法向量,然后通过差值计算出内部每个像素点的法向量,以此来对每个像素进行着色。

三种Shading对比

当组成模型的面片足够多的时候,三种shading的效果就会非常接近。

  • Defining Per-Vertex Normal Vector

顶点法向量

下图中中心点周围有四个三角形,也就是被四个三角形公用,那么这个点的法向量就是这四个三角形的法向量相加求平均。

[math] N_{v} = \frac{\sum _{i}N_{\Im }}{\parallel \sum _{i}N_{\Im }\parallel } [/math]

顶点法向量.png
  • Graphics (Real-time Rendering) Pipeline
图形渲染管线.png

1. 将3D空间中的点映射到屏幕控件(screen space),这一步叫做 Vertex Processing

Vertex-processing.png

2.得到模型的所有顶点后,我们将这些点都连起来得到三角形,也就是Triangle Processing。

3.上一步得到的三角形是连续的,而计算机需要处理离散的数据,所以这里就需要用到光栅化(Rasterizantion),也就是之前

提到的,如何判断一个像素点是在三角形内部还是在三角形外部。通过光栅化可以得到许多fragment(按OpenGL里的说法,也就是片元)。

Rasterization.png

4.接着就开始渲染这些fragment。那么这里救护遇到两个问题: 遮挡 着色

遮挡需要通过深度缓存解决。

FragmentProcessing.png


FragmentProcessing2.png


纹理映射(Texture Mapping)

纹理映射示例

在屏幕空间,三维空间,纹理空间之间建立起映射关系,为每一个像素点提供不同的渲染纹理。

下图左边是渲染之后的模型,右边是对应的纹理,纹理坐标使用UV来表示,同时纹理坐标的范围被限制在0到1之间。

纹理坐标.png

三角形内插值 在之前的PhongShading算法中提到过,需要对每个像素求出法向量,因此要用到插值算法,目的是希望在三角形的

的内部有一个比较平滑的过渡。除了对法向量进行插值,我们也可以读颜色,纹理坐标等进行差值操作。

在插值中会用到重心坐标(Barycentric Coordinates),即使用重心坐标来表示三角形内的任意一点。

重心坐标的计算

下图是重心坐标的示意图。红点是三角形内任意一点,该点的真实坐标是(x,y),重心坐标是[math] \left ( \alpha , \beta ,\gamma \right ) [/math]

真实坐标和重心坐标满足一下关系:该点的直角坐标是三个顶点(A,B,C)坐标的线性组合,且系数相加等于一,三个系数均为非负值。

重心坐标公式

一个三角形的重心坐标也可以用几何形式来表示,即在三角形内任取一点,然后将三个顶点和该点相连,分别计算三个子三角形所占原三角形的面积比即为重心坐标。

其中A是指面积area,即[math] Area_{A} [/math]

[math] \alpha = \frac{A_{A}}{A_{A}+A_{B}+A_{C}} [/math]

[math] \beta = \frac{A_{B}}{A_{A}+A_{B}+A_{C}} [/math]

[math] \gamma = \frac{A_{C}}{A_{A}+A_{B}+A_{C}} [/math]

中心坐标点几何表示

任意一点重心坐标:

重心坐标公式

重心坐标做插值

重心坐标允许我们先算出重心坐标位置,然后使用重心坐标坐标做插值。

比如,在三角形内对任一点做法向量插值,当求出某一点的重心坐标后,该点的法向量为:[math] n_{k}=\alpha n_{A}+\beta n_{B} + \gamma n_{C} [/math]

注意:三维空间中的坐标投影到二维空间后,重心坐标会发生改变。这个问题会在对深度插值的时候遇到,当我们对深度信息进行插值时,不可以在投影后的二维空间中对深度信息做插值,

而是先算出三维空间中的三角形的重心坐标,然后在三维空间中对该点的深度信息做插值。

纹理映射

在经过光栅化后,我们获得的是一个一个的采样点也就是像素,就可以知道中心点(x,y),那么就可以通过差值得到这个点对应的纹理坐标。最后将此纹理坐标对应颜色信息设置到对应的像素即可。

纹理贴图伪代码

纹理放大

纹理映射中可能会出现的问题:纹理放大。也就是说相对于要渲染的物体,纹理的分辨率不够大。比如,我们用一个4×4的纹理去渲染8×8的平面,就会导致纹理的拉伸,造成视觉上的模糊。

双线性插值

为了解决纹理放大的问题,这里要应用双线性插值(Bilinear interpolation)

双线性插值

由于纹理平面是小于要渲染的物体的,那么物体上的一些位置或者说像素对应在纹理上时就不再是一个整数位置,如下图:

双线性插值-像素无法与纹理坐标一一对应

那么就会直接四舍五入取整(也就是找最近的整数点),导致的结果就如上图中最左边的情况,多个像素被填充同一个纹理位置的信息。

而双线性插值就为了获取到一个更加连续的画面。

如下图,以红点左下角的像素中心点[math] u_{0} [/math]作为原点建立坐标系,那么可以得到红点的坐标为(s,t)。

有线性插值的计算公式为: [math] lerp(x,v_{0},v_{1})=v_{0}+x(v_{1}-v_{0}) [/math]

那么就可以得到[math] u_{00} [/math][math] u_{0} [/math] 之间的点 [math] u_{0} [/math] 的值为[math] u_{0}=lerp(s,u_{00},u_{01}) [/math]

[math] u_{00} [/math][math] u_{10} [/math] 之间的点 [math] u_{0} [/math] 的值为[math] u_{0}=lerp(s,u_{00},u_{10}) [/math]

[math] u_{01} [/math][math] u_{11} [/math] 之间的点 [math] u_{0} [/math] 的值为[math] u_{0}=lerp(s,u_{01},u_{11}) [/math]

双线性插值示例

在得出[math] u_{0} [/math][math] u_{1} [/math]后,再对[math] u_{0} [/math][math] u_{1} [/math]再次进行线性插值即可求出红点的值。即[math]f(x,y)=lerp(t,u_{0},u_{1}) [/math]

这里其实就是在横纵两个方向上做插值。

双线性插值示例

2020年终总结

工作总结:

  • 完善平台中视频播放的功能,修改平台的保存机制,重写路径漫游的代码,完善平台的数据存取,对场景树加入数据绑定。完善平台中模型的加载。(3-6月)
  • 修复平台中各种BUG,协助组内同学将各自代码进行合并;在OSG全屏场景加入透明空间;完成三维可视化平台第一个具备基本功能的完整版本。(7-8月)
  • 开始接手管延鑫师兄使用gpu instance实现重建模型的多视点绘制的代码(9月)
  • 开始参与装甲兵学院的坦克训练场项目。(10-11月)
  • 12月末准备去连云港完成716项目的后续结项工作。

占用资源:

  • 一个专硕名额。
  • 一个实验室工位。
  • 一台高性能台式电脑。

自我评价

  • 总结下来,功劳和苦劳基本大于占用实验室资源。
  • 在具体工作方面,获得了很多工程经验,但是感到图形学方面的知识还是有欠缺,后续还要继续补充学习。

2019年度总结


*c#有效代码量2563行。
*参与完成OSG三维可视化平台的路径漫游功能。
重新封装c#的timer,可以实现自定义漫游的暂停时间和间隔时间。

路径漫游
  • 参与完成OSG三维可视化平台的路径漫游的保存与重现。


梳理之前的旧代码,实现再次打开平台后直接读取保存的路径。

漫游的保存
  • 完成OSG三维可视化平台的三维地图标注,包括添加,删除及停止标注。
标注
  • 对OSG三维可视化平台进行安装包的生成。
打包