首页 > 其他分享 >games101-2 透视深度插值矫正与抗锯齿分析

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

时间:2023-12-03 16:44:22浏览次数:37  
标签:抗锯齿 frac 插值 beta 深度 alpha games101 gamma

深度插值的差错原因

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

透视深度插值公式推导

虽然在原空间与投影平面上的三角形可能发生变形,但是它们的重心坐标依然满足一定的关系:
投影平面:
\(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,并且不需要维护颜色表,减少了时间以及空间开销:

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

标签:抗锯齿,frac,插值,beta,深度,alpha,games101,gamma
From: https://www.cnblogs.com/dyccyber/p/17873365.html

相关文章

  • 数学建模之插值法及代码
    发现更多知识,欢迎访问Cr不是铬的个人网站引言数模比赛中,常常需要根据已知的函数点进行数据、模型的处理和分析,而有时候现有的数据是极少的,不足以支撑分析的进行,这时就需要使用一些数学的方法,“模拟产生”一些新的但又比较靠谱的值来满足需求,这就是插值的作用。插值法的定义......
  • 数学基础:三角形重心坐标插值公式的证明
    在快速Phong明暗处理(Blinn-Phong明暗处理)时,出现了三角形重心坐标插值公式,但没有给出证明.网上也鲜有证明过程,这里给出证明.问题描述:在三角形ABC中,三顶点A、B、C坐标分别为\((x_1,y_1,z_1)、(x_2,y_2,z_2)、(x_3,y_3,z_3)\).则三角形内任一点P(x,y,z)可表示为:\[\tag{1}P=\alph......
  • 【scipy 基础】--插值
    插值运算是一种数据处理方法,主要用来填补数据之间的空白或缺失值。因为在实际应用中,数据往往不是完整的,而是存在着空白或缺失值,这些空白或缺失值可能是由于数据采集困难、数据丢失或数据处理错误等原因造成的。如果直接使用这些空白或缺失值进行分析和预测,将会对结果造成很大的影......
  • MATLAB 使用离散数据点实现三维曲面插值
    依靠若干离散点实现三维曲面插值是工程应用中的常见问题,也是数据处理工作的常见需求。MATLAB实现上述功能主要依靠 griddata函数,该函数支持基于三角形的三次插值(仅支持内插值,估计是一种保形插值)和双调和样条插值(支持外插值)。案例数据如下图所示:案例数据空间分布如下:案例代......
  • 【图形学笔记】Lecture02&03 光栅化、抗锯齿、Z-buffer
    目录Lecture02-DigitalDrawing数码绘画Triangles-FundamentalAreaPrimitive三角形——基本区域Rasterization光栅化Sampling采样Lecture03-Sampling,Aliasing,Antialiasing采样、锯齿、抗锯齿Artifactsduetosampling-“Aliasing”采样产生的问题-混叠Antialias......
  • games101一些问题及思考
    games101一些问题及思考1.透视投影为什么z值变大从透视投影矩阵可以看出z会变大,但从直观上怎么想呢。想象一段向无穷远处延伸的铁轨,假设有100m,但照片中前一半明显不足50m,后一段明显多于50m,可以体会到近平面和远平面之间的点都会向远平面压缩,使得出现近大远小的情况。2.各个......
  • 拉格朗日插值法
    今天\(T2\)用到了,于是来学一学。拉格朗日插值法洛谷模板求值是指给定一个函数式,根据一个自变量求出因变量。而插值是给出一些自变量及其对应的因变量,求出符合的函数式。一种方法是将所有的值代入,然后解方程,显然极其不方便,这时,一位名为约瑟夫·路易斯·拉格朗日的人站了出来......
  • 拉格朗日插值
    拉格朗日插值普通拉格朗日插值众所周知,\(n+1\)个横坐标互不相同的点可以确定出唯一的最高次为\(n\)的多项式。当给定你\(n\)个点并要求你求出横坐标为\(x\)的点的纵坐标,高斯消元虽是个选择,但是\(O(n^3)\)的时间复杂度显然不优。于是我们选择用\(O(n^2)\)的拉格朗日......
  • 拉格朗日插值
    拉格朗日插值:给定\(n+1\)个点值\((x_i,y_i)\),对应唯一一个\(n\)次多项式,带入\(f(k)=\sum\limits_{i=1}^{n+1}y_i\prod\limits_{j\neqi}\frac{k-x_j}{x_i-x_j}\)。基本思想就是,构建\(n+1\)个多项式使得\(x=x_i\)时为1,\(x=x_j(j\neqi)\)时为0。当你取的点值连续......
  • 基于亚奈奎斯特采样和SOMP算法的平板脉冲响应空间插值matlab仿真
    1.算法运行效果图预览 2.算法运行软件版本matlab2022a 3.算法理论概述     平板脉冲响应(PulseResponse)是通信和雷达等领域中的重要参数,它描述了信号在空间中传播的特性。在现实应用中,获取完整的脉冲响应通常是耗时且昂贵的。基于亚奈奎斯特采样和SOMP算法的平板脉......