[GAMES101]现代计算机图形学课程总结4:重心坐标,作业2
文章目录
- 重心坐标与三角形内部插值
- 在三角形内部插值
- 为什么要插值
- 哪些属性需要插值
- 如何插值
- 重心坐标:在三角形上使用的一种坐标系统
- 三角形顶点的重心坐标
- 重心坐标的计算:通过三角形面积比
- 重心的重心坐标:
- 重心坐标公式
- 使用重心坐标线性插值
- 作业2总结
- 关于作业框架的一些问题
- 关于作业框架中的透视校正插值
- 实现三角形栅格化算法以及z-buffer算法
- 测试点是否在三角形内的具体算法:
- 实现MSAA (2x2):
- 首先扩大了深度缓冲和颜色缓冲为原先的4倍,并且建立一个masks缓冲来存储sub pixel是否可见。
- 在rasterize_triangle函数中
- 在draw函数中
重心坐标与三角形内部插值
在三角形内部插值
为什么要插值
- 经常要在顶点上设置属性
- 需要在三角形内部得到平滑的值
哪些属性需要插值
- 纹理坐标,颜色,法线,等等。。。
如何插值
- 使用重心坐标(Barycentric coordinates)
重心坐标:在三角形上使用的一种坐标系统
- 使用alpha, beta, gamma三个系数对三角形三个顶点进行线性组合,可以得到三角形所在平面任意点,需要满足条件 alpha+beta+gamma=1
- 如果这三个系数都大于等于0,则该点在三角形内部
三角形顶点的重心坐标
- 对于上图的A点,其重心坐标为(1,0,0),同样对于B点为(0,1,0),C点为(0,0,1)
重心坐标的计算:通过三角形面积比
三个系数分别使用相应顶点对面的小三角形面积比上三角形总面积。
重心的重心坐标:
重心到三个顶点的连线构成的三个三角形的面积相等,因此重心的重心坐标为(1/3,1/3,1/3)
重心坐标公式
使用重心坐标线性插值
- 直接使用alpha, beta, gamma对任意顶点属性进行线性插值
- 注意:在投影变换下,不能保证重心坐标不变。三维空间的三角形中的一点的重心坐标是使用三维空间中的三角形三个顶点计算的,而投影后二维空间的该点的重心坐标是用投影后的三角形三个顶点计算的。这两个重心坐标很可能是不一样的。
- 因此要算三维空间中三角形内一点的插值需要计算出三维空间中的重心坐标,然后使用这个重心坐标插值。而不能使用投影后的2D点计算出重心坐标插值。
- 比如深度插值,如果使用投影后的顶点计算出重心坐标进行深度值的插值其实是错误的。
- 101上讲的方法是要将投影后顶点逆变换回3D空间计算重心坐标再用来插值。工业界常用方法是透视投影校正,这种方法还是使用投影后的坐标计算重心坐标,但是插值时却不直接使用重心坐标。具体参考图形学基础之透视校正插值
作业2总结
关于作业框架的一些问题
s2021(包括s2020)的光栅化部分的作业框架有一点问题,具体可以参考BBS的这个帖子:作业3 关于深度值问题自己踩的坑和一些想法
除了框架本身的小错误外,造成困扰的主要是约定不明,我是完全按照101课程的约定去做的,但是貌似框架不这么想,所以最后深度比较的时候就不能使用小于了,虽然作业框架说深度值都已经转成正数了,越大离视点越远,但如果按101的规范(使用右手坐标系的NDC)的话,简单的反转深度值为正数,实际效果是值越大离视点越近。不过其实弄明白所有的过程也没什么好纠结的了。作业2中我就是把已经反转的z值又取负然后继续用小于来测试。然后在URasterizer中,也是使用了101的约定,我是将-1,1的z值转到0到1,但是没有取反,这样就需要用大于测试,正好和Unity的ReverseZ一样。
关于作业框架中的透视校正插值
作业框架中的重心坐标插值其实是使用了透视校正的方式。
auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();z_interpolated *= w_reciprocal;
在上文引用的图形学基础之透视校正插值中,我们得出一个结论:
这个式子是通过线段内部插值进行推导的,对于三角形,我们使用重心坐标作为插值系数,可以类比得到:
1Zt=alphaZ1+betaZ2+gammaZ3\frac{1}{Z_t} = \frac{alpha}{Z_1} + \frac{beta}{Z_2} + \frac{gamma}{Z_3} Zt1=Z1alpha+Z2beta+Z3gamma
因为我们根据101的约定计算的投影矩阵,将顶点变换到NDC后,其w值就是视图空间的z值。所以框架代码中:
float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
w_reciprocal就是我们上面推导的式子中的ZtZ_tZt,既然如此为啥后面还要计算z_interpolated呢?是因为作业框架中在viewport transform时,将z值映射到了near,far之间:
float f1 = (50 - 0.1) / 2.0;
float f2 = (50 + 0.1) / 2.0;vert.z() = vert.z() * f1 + f2;
按照101的约定,view space的z值是负数,经过这个映射变成了[0.1,50]之间的正数了,所以即便我们使用透视校正插值计算出了真实的view space的z值ZtZ_tZt(也就是框架中的w_reciprocal),也不能直接用来做深度测试。不过没关系,我们可以把这个映射过的z值作为一个顶点属性进行透视校正插值。顶点属性的透视校正插值公式为:
这个式子的分母就是上面的1Zt\frac{1}{Z_t}Zt1,而分子部分是对属性线性插值时每个属性值多除了一个顶点z值。作业框架中,z_interpolated计算的就是分子部分,然后再乘以w_reciprocal(这个就是分母的倒数了,所以用了reciprocal,也就是ZtZ_tZt)就得到了透视校正插值的属性值。
由于可能要做多次插值,所以先将w_reciprocal计算出来,就可以方便插值时再乘一下了。在作业3中是这么做的,注释比作业2的清晰多了:
// * v[i].w() is the vertex view space depth value z.
// * Z is interpolated view space depth for the current pixel
// * zp is depth between zNear and zFar, used for z-bufferfloat Z = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
float zp = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
zp *= Z;
然后下面插值各个属性,原始是普通的线性插值:
// Interpolate the attributes:
auto interpolated_color = alpha * t.color[0] + beta * t.color[1] + gamma * t.color[2];
auto interpolated_normal = alpha * t.normal[0] + beta * t.normal[1] + gamma * t.normal[2];
auto interpolated_texcoords = alpha * t.tex_coords[0] + beta * t.tex_coords[1] + gamma * t.tex_coords[2];
auto interpolated_shadingcoords = alpha * view_pos[0] + beta * view_pos[1] + gamma * view_pos[2];
可以改成透视校正插值:
// Interpolate the attributes:
auto interpolated_color = (alpha * t.color[0]/v[0].w() + beta * t.color[1]/v[1].w() + gamma * t.color[2]/v[2].w()) * Z;
//下同
实现三角形栅格化算法以及z-buffer算法
rasterize_triangle函数中
首先计算当前三角形的AABB,判断三个顶点的x,y的极大极小值得到。
根据AABB计算出需要采样的像素坐标,通过floor,ceil以及边界检测得到。
遍历需要检测的像素,在没有MSAA的情况下,判断每个像素是否在三角形内部,
如果在内部则计算重心坐标插值后的深度值,使用深度值和深度缓冲中该像素位置的值进行比较
如果通过深度测试则写入深度值,同时取三角形的颜色值写入frame_buf
测试点是否在三角形内的具体算法:
insideTriangle函数中,
首先像素坐标加上偏移值得到sampler位置。对于非MSAA,sampler位置取像素中心,偏移值为(0.5,0.5)
分别计算从三个顶点出发到sampler的向量,以及按环绕顺序计算三个顶点到下一个顶点的向量。
计算向量的叉积,如果该叉积和上一个叉积的z值的符号相同则继续计算。
所有三个叉积的z值符号都相同则该点在三角形内部。
实现MSAA (2x2):
首先扩大了深度缓冲和颜色缓冲为原先的4倍,并且建立一个masks缓冲来存储sub pixel是否可见。
std::vectorEigen::Vector4f depth_buf_2x2;
std::vectorEigen::Vector3f sampler_colors[4];
std::vectorEigen::Vector4f sampler_colors_masks;
在rasterize_triangle函数中
对于每个需要遍历的像素,使用2x2共4个sampler判断是否在三角形内,如果在内,则分别计算每个sub pixel的深度值,
并使用depth_buf_2x2缓冲进行深度测试,如果通过测试则写入该缓冲,同时将颜色值记录到sampler_colors中,
并且sampler_colors_masks该sub pixel的值设置为1。
在draw函数中
所有三角形光栅化完毕后,增加一个Resolve AA的过程:
遍历所有像素,检查他们的子像素的masks值是否为1,如果是将颜色取出进行平均,得到的颜色值设置给该像素。注意平均时的分母是4,而不是masks为1的子像素数目。
[GAMES101]现代计算机图形学课程总结4:重心坐标,作业2相关推荐
- [GAMES101]现代计算机图形学课程总结3:Shading
文章目录 概要 Shading的定义 Shading是局部的 输入 不产生阴影(shading不等于shadow) Blinn-Phong Reflectance Model 漫反射 (Diffuse ...
- 闫令琪:Games101 现代计算机图形学-光线追踪(三):渲染方程和路径追踪path ray tracing 作业Assignment07解析
文章目录 0 whitted光线追踪的局限 1 辐射度量学 1.1 光线的表示 Radiance 1.2 物体表面上一个点的亮度 Irradiance 1.3 BRDF(Bidirectional R ...
- 一篇学完:GAMES101:现代计算机图形学入门 学习笔记
文章首发于lengyueling.cn 欢迎访问交流! PDF版本已经附在lengyueling.cn文章末尾,需要自取. 导论 图形学应用场景 电子游戏: PBR:之狼 卡通渲染:无主之地 电影:黑 ...
- GAMES101现代计算机图形学入门-第一节-图形学导论
最近在为之后找工作面试做准备,所以把大二学习的计算机图形学又拿出来重新学起来了,也推荐大家一起看闫大神的课!!! 然后笔记是在lengyueling大佬的版本上进行的修改,总体还是大佬的模板. 希望大 ...
- GAMES101现代计算机图形学入门——几何表示之曲线与曲面
此为个人学习笔记,总结内容来源于网络各个平台,如有错误欢迎指摘 几何表示 曲线与曲面 本节附加资料: Making things with Maths (acko.net) 游戏开发技术杂谈2:理解插 ...
- Games101 计算机图形学课程笔记: Lecture14 Ray Tracing 2
目录 加速结构 均匀空间划分(Uniform Spatial Partitions) 空间划分 空间划分例子 KD-Tree KD-Tree存储数据结构 KD-Tree结构中进行光线追踪 KD-Tre ...
- Games101 计算机图形学课程笔记: Lecture 08 Shading 2 (Shading, Pipeline and Texture Mapping)
目录 Specular Term (Blinn-Phong) Specular Term 高光项 Ambient Term 环境项 Blinn-Phong Reflection模型效果 着色频率 fl ...
- Games101 计算机图形学课程笔记:Lecture 19 Cameras, Lenses and Light Fields
目录 相机 快门与传感器 针孔相机 视场 Field of View(FOV) 曝光 Exposure ISO 光圈 快门 薄透镜近似 Thin Lens Approximation 薄透镜方程 De ...
- Games101 计算机图形学课程笔记: Lecture 10 Geometry 1 (Introduction)
目录 Applications of Textures Environment Map 凹凸贴图 位移贴图 三维纹理 几何 隐式表示 Algebraic Surfaces Constructive S ...
最新文章
- 新一代人工智能专利分析
- 轴固定位置_3轴、3+2轴、5轴加工都有哪些区别?这篇文章给你整明白
- 采用Atlas+Keepalived实现MySQL读写分离、读负载均衡【转载】
- html5储存类型特点,避免踩雷!你不得不知的 HTML5 “新”特性
- Python3.0 新特性
- 企业平均每年遭遇9起有针对性攻击
- Hibernate之ID生成规则
- Hive增加一列固定值
- python函数手册中文,python函数中文手册.doc
- 苹果12隔空投送显示无法连接服务器,iOS设备隔空投送功能无法使用该如何解决...
- 产生式系统有哪几种推理方式?各自的特点?
- STM32F107各种接口程序合集工程文件
- win7 共享计算机 网络密码怎么设置,win7局域网共享设置密码 win7局域网如何设置密码【详细步骤】...
- 爬取图片案例2(Ajax网页异步加载、Queue队列、线程池)
- vue 页面刷新404
- 手动连接wifi失败分析
- 谷歌浏览器(Chrome)输入框总是有历史输入记录,解决办法
- AppsFlyer的测试
- 计算机音乐谱安娜的橱窗,钢琴谱 - 安娜的橱窗(2)
- [离散数学] 关于p - q的理解。