games101-2 透视深度插值矫正与抗锯齿分析

这篇具有很好参考价值的文章主要介绍了games101-2 透视深度插值矫正与抗锯齿分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 透视深度插值矫正与抗锯齿分析
    • 深度插值的差错原因
    • 透视深度插值公式推导
    • games101中的错误
    • msaa与ssaa简要定义
    • games101中ssaa的实现
    • games101中msaa的实现

深度插值的差错原因

games101-2  透视深度插值矫正与抗锯齿分析
当投影的图形与投影的平面不平行时,这时进行透视投影,从上图中可以看出,投影平面上的线段时均匀的,但是在原图形上的线段是非均匀的,这只是一个例子,但也可以看出投影会导致图形的变形,在我们利用重心坐标,进行深度插值时原空间中的重心坐标会发生变形,导致我们得到的深度不是正确的,这一点在对纹理坐标进行插值时尤其明显

透视深度插值公式推导

虽然在原空间与投影平面上的三角形可能发生变形,但是它们的重心坐标依然满足一定的关系:
投影平面:
\(1 = \alpha^{'} +\beta^{'} +\gamma^{'}\)

原空间:
\(1 = \alpha +\beta +\gamma\)

现在我们只有投影平面上三角形的bounding box中一个个像素点,我们想要得到这个像素点真实的深度值,假设一个像素点真实的深度值为\(Z\),三角形三个顶点真实的深度值分别为\(Z_{a},Z_{b},Z_{c}\),我们对第一个式子进行恒等变形:

$\frac{Z}{Z} = \frac{Z_{a}}{Z_{a}}\alpha^{'} + \frac{Z_{b}}{Z_{b}}\beta^{'} + \frac{Z_{c}}{Z_{c}}\gamma^{'} $

进一步变换得到:
\(Z = (\frac{Z}{Z_{a}}\alpha^{'})Z_{a} + (\frac{Z}{Z_{b}}\beta^{'})Z_{b} + (\frac{Z}{Z_{c}}\gamma^{'})Z_{c}\)

我们对照原空间的深度重心插值公式:
\(Z = \alpha Z_{a} + \beta Z_{b} + \gamma Z_{c}\)

可以得到:
\(\alpha = \frac{Z}{Z_{a}}\alpha^{'}\)
\(\beta = \frac{Z}{Z_{b}}\beta^{'}\)
\(\gamma = \frac{Z}{Z_{c}}\gamma^{'}\)

我们再代入之前的第二个式子:
\(1 = \frac{Z}{Z_{a}}\alpha^{'} + \frac{Z}{Z_{b}}\beta^{'} + \frac{Z}{Z_{c}}\gamma^{'}\)

两边同时除以\(Z\):
$\frac{1}{Z} = \frac{1}{Z_{a}}\alpha^{'} + \frac{1}{Z_{b}}\beta^{'} + \frac{1}{Z_{c}}\gamma^{'} $

我们可以进一步考虑更一般的情况,对任意属性(uv坐标颜色法线等)使用重心坐标进行插值:
\(I = \alpha I_{a} + \beta I_{b} + \gamma I_{c}\)

\(I = Z(\alpha^{'}\frac{I_{a}}{Z_{a}} + \beta^{'}\frac{I_{b}}{Z_{b}} + \gamma^{'}\frac{I_{c}}{Z_{c}} )\)

games101中的错误

有了上述理论基础,我们再来看看games101中的实现:

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();

注意在前面:

auto v = t.toVector4();

games101将一个三维向量拓展为四维向量,理论上一个像素点的坐标应该是(x,y,z,w),其中x,y代表投影的xy坐标,z代表压缩之后的z值,一般在[-1,1]或者[0,1]或者[n,f]之间,w一般用于存储原空间真实的深度值,但是上述拓展默认将w设置为1,w存储的不是真实的深度值,因此:

float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());

这一步使用的深度值是错误的

假如是正确的,其实这一步得到的w_reciprocal已经是正确的深度矫正值,也不需要在后面再求z值

但是最终结果我们也没有发现明显的错误,可以认为即使使用错误的深度值,对最终结果也影响不大

msaa与ssaa简要定义

MSAA:多重采样抗锯齿是一种选择性的抗锯齿技术,它在渲染图像时对特定部分进行多次采样。通常,它会对几何边缘周围进行多次采样,以减少锯齿状边缘的出现。
SSAA:超级采样抗锯齿是一种全局的抗锯齿技术,它通过在整个图像上进行更高分辨率的采样,然后缩放到目标分辨率,从而减少锯齿和增强图像的质量。

games101中ssaa的实现

ssaa实现的是更高分辨率的采样,为了实现这一点我们需要为每个采样点都维护深度表与颜色表,在对每个采样点进行覆盖检测以及深度检测之后,将采样点的颜色进行平均,设置为像素点颜色:

for(int x=min_x; x<=max_x; x++) {
        for(int y=min_y; y<=max_y; y++) {
            int eid = get_index(x,y)*4;
            for(int k = 0; k < 4; k++){//遍历像素的每个样本
                if(insideTriangle(x+a[k], y+a[k+1], v.data())){
                   //计算重心坐标
                   auto[alpha, beta, gamma] = computeBarycentric2D(x+a[k],y+a[k+1], 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;
                   //如果此时深度值大于当前存储深度值,说明被遮挡了,不做处理
                   if (depth_sample[eid + k] < z_interpolated) {
                       continue;
                   }
                   //反之,更新当前深度值,对采样点进行着色
                    depth_sample[eid + k] = z_interpolated;
                    frame_sample[eid + k] = t.getColor();
                }
            }
            Eigen::Vector3f p;
            p << x, y, 1;
            //平均四个采样点的颜色,简单的线性混合
            Eigen::Vector3f color = (frame_sample[eid] + frame_sample[eid + 1] + frame_sample[eid + 2] + frame_sample[eid + 3])/4;
            set_pixel(p, color);
        }
    }

games101中msaa的实现

msaa与ssaa类似,也是对四个采样点的颜色进行混合,也需要对采样点进行覆盖以及深度检测,不过不同的时,msaa会记录深度的变化,只有在深度发生变化,认为检测到边缘的时候,才会进行shading,并且不需要维护颜色表,减少了时间以及空间开销:文章来源地址https://www.toymoban.com/news/detail-747907.html

for(int x=min_x; x<=max_x; x++) {
        for(int y=min_y; y<=max_y; y++) {
            //使用msaa方法,统计像素覆盖率
            int eid = get_index(x,y)*4;
            //统计像素的覆盖率与深度变化
            float count_coverage = 0,count_depth = 0;
            for(int k = 0; k < 4; k++){//遍历像素的每个样本
                if(insideTriangle(x+a[k], y+a[k+1], v.data())){
                   auto[alpha, beta, gamma] = computeBarycentric2D(x+a[k],y+a[k+1], 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;
                   //如果该采样点在三角形内,增加覆盖率的计数
                   count_coverage++;
                    if (depth_buf[eid + k] < z_interpolated) {
                       continue;
                    }
                    //如果该采样点的深度发生了变化,说明该像素分布在边缘,需要进行抗锯齿
                    count_depth++;
                    depth_buf[eid + k] = z_interpolated;
                }
            }
            //如果该像素在边缘,需要进行抗锯齿
            if(count_depth > 0){
                int ind = get_index(x,y);
                Eigen::Vector3f p;
                p << x, y, 1;
                //混合颜色
                Eigen::Vector3f color = (count_coverage / 4)*t.getColor() +(1 - count_coverage/4)*frame_buf[ind];
                set_pixel(p, color);
            }
        }
    }

到了这里,关于games101-2 透视深度插值矫正与抗锯齿分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • games101-3 BRDF101

    本文基于知乎Maple对brdf的文章,在此基础又收集了一些其它来源的关于brdf的文章,希望能够完全理解记忆相关知识 关于Jakub Boksansky的文章,看的过程中又去搜集了很多其它文章来理解,发现已经超出了我目前的知识厚度,因此只会简单的翻译一下我能理解的部分,感兴趣的

    2024年04月25日
    浏览(32)
  • GAMES101 作业1

    作业pa1对应的是GAMES101课程Lecture02到Lecture04这三节课的内容,主要是用于巩固空间中的物体投影到相机平面的整个过程。 说在前面,本文是在左手系下进行讨论的。 粗略地看一遍我们可以知晓main函数的流程: ①设定一些基本的初始参数并初始化源代码给出的 光栅化类raste

    2024年02月09日
    浏览(33)
  • GAMES101作业2

    在屏幕上画出一个实心三角形, 换言之,栅格化一个三角形。上一次作业中,在视口变化之后,我们调用了函数 rasterize_wireframe(const Triangle t)。但这一次,你需要自己填写并调用 函数 rasterize_triangle(const Triangle t)。 该函数的内部工作流程如下: 创建三角形的 2 维 bounding box。

    2024年02月16日
    浏览(41)
  • GAMES101:作业7记录

    在之前的练习中,我们实现了 Whitted-Style Ray Tracing 算法,并且用 BVH等加速结构对于求交过程进行了加速。在本次实验中,我们将在上一次实验的基础上实现完整的 Path Tracing 算法。至此,我们已经来到了光线追踪版块的最后一节内容。 请认真阅读本文档,按照本文档指示的流程完成

    2024年02月01日
    浏览(45)
  • GAMES101:作业3

    附其他所有作业超链接如下: Games101 作业0: 作业0 Games101 作业1: 作业1 Games101 作业2: 作业2 Games101 作业3: 作业3 Games101 作业4: 作业4 Games101 作业5: 作业5 Games101 作业6: 作业6 Games101 作业7: 作业7 完整代码获取途径: https://github.com/liupeining/Games_101_homework 照旧把这段代码

    2024年02月04日
    浏览(37)
  • Games101学习笔记1

    2023-08-10开始接触图形学 参考博客:GAMES101 梳理 / 个人向图形学笔记_games101笔记_river_of_sebajun的博客-CSDN博客  向量的长度 向量的单位化  向量的点乘 点乘结果是一个数字,叉乘结果是垂直已知向量的向量  b向量投影到a向量上  矩阵的乘法 二维变换 线性变换    切边  旋转

    2024年02月13日
    浏览(35)
  • GAMES101 作业0

    课上提供的环境是Linux, 还需要安装Vitrual Box和创建虚拟机,省事就直接在Windows系统下Visual Studio下操作了。 简单的环境配置: 下载Eigen 的库 在工程属性中添加目录: 2处地方 注意: 刚添加完后,我新建main.cpp后, 引入头文件 路径也没有设置错啊,但是就是找不到。 直到看

    2024年02月16日
    浏览(40)
  • games101 作业3

    1.项目才打开时无法运行。 解决方法: 切换成c++17 解决方法引用: Games101 作业3 环境问题 - 知乎  注:知乎里面的关于越界限制的控制不适用,虽然可以解决部分作业的问题,但是在bump里面依然会出现越界错误。应该用以下大佬的代码。  2.出现越界错误   解决方法: 在头

    2023年04月25日
    浏览(35)
  • 【GAMES101】03 Transformation

    1、Scale(缩放)  2、Reflection Matrix(反射矩阵)  3、Shear Matrix(剪切矩阵)  4、Rotation Matrix(旋转矩阵) 推导过程:     5、Translation Matrix(平移矩阵) 平移操作不属于线性变换的范畴。 引入 齐次坐标 ,通过增加维度,来将平移坐标写成同样的矩阵形式。 很显然,平移无

    2024年02月02日
    浏览(39)
  • Games101作业5解读

    在scene中加入两个球一个地板和两个点光源 在Render中我们从eye_pos向屏幕打出一根一根的ray与场景相交 第一步先与场景的求交,如果光线打到了物体,就继续判断打到的物体的材质,根据不同的材质进行不同的处理,这里重点说下REFLECTION和default 在REFLECTION中,这一段代码有点问

    2024年02月09日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包