PBRT_V2 总结记录 <45> Texture Sampling Rate 和 DifferentialGeometry->ComputeDifferentials

该博客探讨了如何通过偏导数来理解和计算纹理采样率,用于实现纹理抗锯齿。在DifferentialGeometry类中,ComputeDifferentials方法计算了dpdx, dpdy, dudx, dvdx, dudy, dvdy等,这些值用于关联像素采样点变化与纹理采样点的变化。文章详细解释了如何通过辅助射线与切平面的交点来估算表面位置的偏导数,并介绍了如何处理可能出现的线性系统过约束问题。" 129358049,9863761,STC单片机硬件I2C驱动OLED显示DS18B20温度教程,"['STC8单片机', '硬件I2C驱动', 'OLED显示', '温度传感器', 'DS18B20']
摘要由CSDN通过智能技术生成

理论基础:

Fortunately, for texture antialiasing, we don’t need to be able to evaluate f (x, y) for arbitrary (x, y), but just need to find the relationship between changes in pixel sample position and the resulting change in texture
sample position at a particular point on the image.
This relationship is given by the partial
derivatives of this function, ∂f/∂x and ∂f/∂y. For example, these can be used to find
a first-order approximation to the value of f ,

If these partial derivatives are changing slowly with respect to the distances x’ − x and
y‘ − y, this is a reasonable approximation. More importantly, the values of these partial
derivatives give an approximation to the change in texture sample position for a shift of
one pixel in the x and y directions, respectively, and thus directly yield the texture sampling
rate.

(实现Texture的抗锯齿,我门需要去发现,假如改变了像素采样点的位置, 那么会导致 纹理采样点位置 发生怎么样的变化 ,个人理解就是,当像素采样点的间距变化了,那么纹理采样点的间距会怎么变化呢?需要找出这两者之间的关系,

那么 偏导数就可以 说明到这样的关系,例如之后会 计算 ∂u/∂x,  ∂u/∂y, ∂v/∂x,  ∂v/∂y, 就 ∂u/∂x 偏导数的 意义就是,当前像素的采样点 偏移了 Δx, 那么 对应 偏移了多少 Δu,这样就可以把 像素采样点的位置变化 与 纹理采样点的位置变化关联起来了)

 

 

实现:

DifferentialGeometry 类:

// DifferentialGeometry Declarations
struct DifferentialGeometry {
    DifferentialGeometry() { 
        u = v = dudx = dvdx = dudy = dvdy = 0.; 
        shape = NULL; 
    }
    // DifferentialGeometry Public Methods
    DifferentialGeometry(const Point &P, const Vector &DPDU,
            const Vector &DPDV, const Normal &DNDU,
            const Normal &DNDV, float uu, float vv,
            const Shape *sh);
    void ComputeDifferentials(const RayDifferential &r) const;

    // DifferentialGeometry Public Data
    Point p;
    Normal nn;
    float u, v;
    const Shape *shape;
    Vector dpdu, dpdv;
    Normal dndu, dndv;
    mutable Vector dpdx, dpdy;
    mutable float dudx, dvdx, dudy, dvdy;
};

 

1. 
void DifferentialGeometry::ComputeDifferentials(
        const RayDifferential &ray) const 

作用:

(ComputeDifferentials 方法里面,主要是计算 dpdx, dpdy, dudx, dvdx, dudy, dvdy, 其他的 dpdu, dpdv, dndu, dndv ,都是在  virtual bool Shape::Intersect(const Ray &ray, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const 中计算,需要注意一下这个方法的调用时机,在 Intersection::GetBSDF() 里面直接调用,但是 在 Material GetBSDF()之前,主要是在使用Texture之前,先把数据计算好。

BSDF *Intersection::GetBSDF(const RayDifferential &ray,
                            MemoryArena &arena) const {
    PBRT_STARTED_BSDF_SHADING(const_cast<RayDifferential *>(&ray));
    dg.ComputeDifferentials(ray);
    BSDF *bsdf = primitive->GetBSDF(dg, ObjectToWorld, arena);
    PBRT_FINISHED_BSDF_SHADING(const_cast<RayDifferential *>(&ray), bsdf);
    return bsdf;
}

The DifferentialGeometry::ComputeDifferentials() method computes these values.  dpdx, dpdy,dudx, dvdx, dudy, dvdy;
It is called by Intersection::GetBSDF() and Intersection::GetBSSRDF() before the
Material GetBSDF() or GetBSSRDF() method is called so that these values will be available

for any texture evaluation routines that are called by the material. Because ray differentials
aren’t available for all rays traced by the system

 

2.  dpdx, dpdy, dudx, dvdx, dudy, dvdy 表示:

(dx,dy 表示的是 屏幕x轴,y轴偏移一个 像素采样点,

dpdx,dpdy 表示 屏幕中x,y轴偏移一个像素采样点,对应世界坐标点p 会怎么偏移,

同样的道理, dudx, dvdx, dudy, dvdy 表示 屏幕中x,y轴偏移一个像素采样点, 对应的 texture 的 (u,v) 坐标怎么偏移)

Because the differential rays are offset one pixel sample in each direction, there’s no need
to divide these differences by a Δ value, since Δ = 1.

 

3. void DifferentialGeometry::ComputeDifferentials(
        const RayDifferential &ray) const 

代码:


void DifferentialGeometry::ComputeDifferentials(
        const RayDifferential &ray) const {
    if (ray.hasDifferentials) {
        // Estimate screen space change in $\pt{}$ and $(u,v)$

        // Compute auxiliary intersection points with plane
        float d = -Dot(nn, Vector(p.x, p.y, p.z));
        Vector rxv(ray.rxOrigin.x, ray.rxOrigin.y, ray.rxOrigin.z);
        float tx = -(Dot(nn, rxv) + d) / Dot(nn, ray.rxDirection);
        if (isnan(tx)) goto fail;
        Point px = ray.rxOrigin + tx * ray.rxDirection;
        Vector ryv(ray.ryOrigin.x, ray.ryOrigin.y, ray.ryOrigin.z);
        float ty = -(Dot(nn, ryv) + d) / Dot(nn, ray.ryDirection);
        if (isnan(ty)) goto fail;
        Point py = ray.ryOrigin + ty * ray.ryDirection;
        dpdx = px - p;
        dpdy = py - p;

        // Compute $(u,v)$ offsets at auxiliary points

        // Initialize _A_, _Bx_, and _By_ matrices for offset computation
        float A[2][2], Bx[2], By[2];
        int axes[2];
        if (fabsf(nn.x) > fabsf(nn.y) && fabsf(nn.x) > fabsf(nn.z)) {
            axes[0] = 1; axes[1] = 2;
        }
        else if (fabsf(nn.y) > fabsf(nn.z)) {
            axes[0] = 0; axes[1] = 2;
        }
        else {
            axes[0] = 0; axes[1] = 1;
        }

        // Initialize matrices for chosen projection plane
        A[0][0] = dpdu[axes[0]];
        A[0][1] = dpdv[axes[0]];
        A[1][0] = dpdu[axes[1]];
        A[1][1] = dpdv[axes[1]];
        Bx[0] = px[axes[0]] - p[axes[0]];
        Bx[1] = px[axes[1]] - p[axes[1]];
        By[0] = py[axes[0]] - p[axes[0]];
        By[1] = py[axes[1]] - p[axes[1]];
        if (!SolveLinearSystem2x2(A, Bx, &dudx, &dvdx)) {
            dudx = 0.; dvdx = 0.;
        }
        if (!SolveLinearSystem2x2(A, By, &dudy, &dvdy)) {
            dudy = 0.; dvdy = 0.;
        }
    }
    else {
fail:
        dudx = dvdx = 0.;
        dudy = dvdy = 0.;
        dpdx = dpdy = Vector(0,0,0);
    }
}

 

细节

a. 计算 dpdx, dpdy

// Compute auxiliary intersection points with plane
        float d = -Dot(nn, Vector(p.x, p.y, p.z));
        Vector rxv(ray.rxOrigin.x, ray.rxOrigin.y, ray.rxOrigin.z);
        float tx = -(Dot(nn, rxv) + d) / Dot(nn, ray.rxDirection);
        if (isnan(tx)) goto fail;
        Point px = ray.rxOrigin + tx * ray.rxDirection;
        Vector ryv(ray.ryOrigin.x, ray.ryOrigin.y, ray.ryOrigin.z);
        float ty = -(Dot(nn, ryv) + d) / Dot(nn, ray.ryDirection);
        if (isnan(ty)) goto fail;
        Point py = ray.ryOrigin + ty * ray.ryDirection;
        dpdx = px - p;
        dpdy = py - p;

作用:

(计算 dpdx, dpdy,先确定一个平面,这个平面就是 这个相交点 的 位置 P 和法线 组成的,利用 ray-plane 相交的公式就可以计算出 两条 rays rx,ry 的交点 px, py,那么计算 dpdx,dpdy,用到了dx,dy,因为都是偏移一个像素采样点,所以dx,dy 都是1,那么 得到

For this approximation,
we need the plane through the point intersected by the main ray that is tangent to the
surface. This plane is given by the implicit equation

where a = nx, b = ny, c = nz, and d =−(n · p). We can then compute the intersection
points px and py between the auxiliary rays rx and ry with this plane (Figure 10.3). These
new points give an approximation to the partial derivatives of position on the surface
∂p/∂x and ∂p/∂y, based on forward differences:

Because the differential rays are offset one pixel sample in each direction, there’s no need
to divide these differences by a Δ value, since Δ = 1.

The ray–plane intersection algorithm gives the t value where a ray described by origin o
and direction d intersects a plane described by ax + by + cz + d = 0:

To compute this value for the two auxiliary rays, the plane’s d coefficient is computed
first. It isn’t necessary to compute the a, b, and c coefficients, since they’re available in
dg.nn.We can then apply the formula directly.

Figure 10.3: By approximating the local surface geometry at the intersection point with the tangent
plane through p, approximations to the points at which the auxiliary rays rx and ry would intersect
the surface can be found by finding their intersection points with the tangent plane px and py.

 

2. 

float A[2][2], Bx[2], By[2];
        int axes[2];
        if (fabsf(nn.x) > fabsf(nn.y) && fabsf(nn.x) > fabsf(nn.z)) {
            axes[0] = 1; axes[1] = 2;
        }
        else if (fabsf(nn.y) > fabsf(nn.z)) {
            axes[0] = 0; axes[1] = 2;
        }
        else {
            axes[0] = 0; axes[1] = 1;
        }

        // Initialize matrices for chosen projection plane
        A[0][0] = dpdu[axes[0]];
        A[0][1] = dpdv[axes[0]];
        A[1][0] = dpdu[axes[1]];
        A[1][1] = dpdv[axes[1]];
        Bx[0] = px[axes[0]] - p[axes[0]];
        Bx[1] = px[axes[1]] - p[axes[1]];
        By[0] = py[axes[0]] - p[axes[0]];
        By[1] = py[axes[1]] - p[axes[1]];
        if (!SolveLinearSystem2x2(A, Bx, &dudx, &dvdx)) {
            dudx = 0.; dvdx = 0.;
        }
        if (!SolveLinearSystem2x2(A, By, &dudy, &dvdy)) {
            dudy = 0.; dvdy = 0.;
        }

作用:

(计算 dudx,dvdx, dvdy, dvdy,  值得注意的是,最后计算出来的 Δu,Δv 其实就是 dudx,dvdx, .... , 因为上面有说,Δ x 其实就是一个像素采样点的偏移,Δ 为1)

Figure 10.4: An estimate of the difference in (u, v) parametric coordinates from p to p' can be found
by finding the coordinates of p' with respect to the coordinate system defined by p, ∂p/∂u, and ∂p/∂v.

 

Given a position p' on the plane, we can compute its position with respect to the coordinate
system by

or, equivalently,

A solution to this linear system of equations for one of the auxiliary points p' = px
or p' = py gives the corresponding screen space partial derivatives (∂u/∂x, ∂v/∂x) or
(∂u/∂y, ∂v/∂y), respectively

 

This linear system has three equations with two unknowns(3个表达式,但是每一个表达式有2个未知数)—that is, it’s overconstrained(无解).
We need to be careful since one of the equations may be degenerate—for example, if
∂p/∂u and ∂p/∂v are in the xy plane such that their z components are both zero, then
the third equation will be degenerate. To deal with this case, because we only need two
equations to solve the system, we’d like to choose the two that won’t lead to a degenerate
system. An easy way to do this is to take the cross product of ∂p/∂u and ∂p/∂v, see which
coordinate of the result has the largest magnitude, and use the other two. Their cross
product is already available in nn, so using this approach is straightforward. Even after
all this, it may happen that the linear system has no solution (usually due to the partial
derivatives not forming a coordinate system on the plane). In that case, all that can be
done is to return arbitrary values.

(3个表达式,但是每一个表达式有2个未知数,那么这个 linear system 是无解的,那么 解这个 linear system 的话,其实只需要2个表达式,一种方案就是, 利用 ∂p/∂u and ∂p/∂v 计算出 法线出来,取法线最小的2个轴,假如,法线的x,y 轴分量最小,那么表达式就取 x,y 的表达式)

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值