Fork me on GitHub

PBR-Book Ch8 Reflection Models

PBR-Book Ch8 Reflection Models

Reflection Models (pbr-book.org)

球坐标系中,使用 \((\theta, phi)\)

  • \(\theta\)

    • given direction to the \(z\) axis
  • \(\phi\)

    • the angle formed with the \(x\) axis after projection of direction onto the \(xy\) lane.

Given a direction vector \(\omega\)

\[\cos \theta = (\bold n \cdot \omega) = ((0, 0, 1) \cdot \omega) = \omega_z \tag{8.1} \]

  • BSDF Inline Functions

\[\cos\theta = \omega_z \\ \cos^2\theta = \omega_z^2 \\ |\cos\theta| = |\omega_z| \]

inline Float CosTheta(const Vector3f &w) { return w.z; }
inline Float Cos2Theta(const Vector3f &w) { return w.z * w.z; }
inline Float AbsCosTheta(const Vector3f &w) { return std::abs(w.z); }

确保 \(\sin^2\theta > 0\)

\[\sin^2\theta = \max(0, 1-\cos^2\theta) \\ \sin\theta = \sqrt{\sin^2\theta} \]

inline Float Sin2Theta(const Vector3f &w) {
    return std::max((Float)0, (Float) 1 - Cos2Theta(w));
}
inline Float SinTheta(const Vector3f &w) {
    return std::sqrt(Sin2Theta(w));
}

\[\tan \theta = \frac{\sin\theta}{\cos\theta} \\ \tan^2 \theta = \frac{\sin^2\theta}{\cos^2\theta} \]

inline Float TanTheta(const Vector3f &w) {
    return SinTheta(w) / CosTheta(w);
}
inline Float Tan2Theta(const Vector3f &w) {
    return Sin2Theta(w) / Cos2Theta(w);
}

image-20240831104628257

如上图,假设 \(\omega\) 是单位向量

\[r = \sin \theta \\ \cos \phi = \frac{x}{r} = \frac{x}{\sin\theta} \\ \sin \phi = \frac{y}{r} = \frac{y}{\sin \theta} \]

inline FLoat CosPhi(const Vector3f &w) {
	Float sinTheta = SinTheta(w);
    return (sinTheta == 0) ? 1 : Clamp(w.x / sinTheta, -1, 1);
}
inline Float SinPhi(const Vector3f &w) {
    Float sinTheta = SinTheta(w);
    return (sinTheta == 0) ? 0 : Clamp(w.y / sinTheta, -1, 1);
}

这里是这样设定的,当 \(\sin \theta = 0\) 时,\(\theta = 0\)\(\theta = \pi\),也就是 \(\omega\) 沿着 \(z\) 轴正向或者负向,此时 \(\phi\) 值其实是未定义的,因为在 \(xOy\) 平面上没有投影

这里设定 \(\cos\phi = 1\)\(\sin\phi = 0\) 其实是为了算法的健壮性和一致性

简单来想可以认为 \(\theta = 0\)\(\theta = \pi\) 时,\(\phi = 0\) (其实 \(\phi\) 没有意义)

\[\cos ^ 2 \phi = \frac{x^2}{\sin^2\theta} \\ \sin ^ 2 \phi = \frac{y^2}{\sin^2\theta} \]

inline Float Cos2Phi(const Vector3f &w)
{
    return CosPhi(w) * CosPhi(w);
}
inline Float Sin2Phi(const Vector3f &w)
{
    return CosPhi(w) * CosPhi(w);
}

The cosine of the angle \(\color{red}{\Delta \phi}\) between two vectors' \(\phi\) values in the shading coordinate system can be found by zeroing the \(z\) coordinate of the two vectors to get 2D vectors and then normalizing them. The dot product of these two vectors gives the cosine of the angle between them. The implementation below rearranges the terms a bit for efficiency so that only a single square root operation needs to be performed.

\[\cos \Delta\phi = \frac{\omega_a \cdot \omega_b}{|\omega_a||\omega_b|} \]

// cosine of Delta Phi
inline Float CosDPhi(const Vector3f &wa, const Vector3f &wb) {
    return Clamp((wa.x * wb.x + wa.y * wb.y) /
                 std::sqrt((wa.x * wa.x + wa.y * wb.y) * 
                           (wb.x * wb.x + wb.y * wb.y)), -1, 1);
}

Keep in Mind

  1. The incident light direction \(\omega_i\) and the outgoing viewing direction \(\omega_o\) will both be normalized and outward facing after being transformed into the local coordinate system at the surface.

    \(\omega_i\)\(\omega_o\) 都是归一化的,且都被变换到局部坐标空间了

  2. By convention in pbrt, the surface normal \(\bold n\) always points to the "outside" of the object, which makes it easy to determine if light is entering or exiting transmissive objects:

    • if the incident light direction \(\omega_i\) is in the same hemisphere as \(\bold n\), then light is entering
    • otherwise, it's exiting.

    Therefore, one detail to keep in mind is that the normal may be on the opposite side of the surface than one or both of the \(\omega_i\) and \(\omega_o\) direction vectors. Unlike many other renderers, pbrt does not flip the normal to lie on the same side as \(\omega_o\)

    \(\omega_i\)\(\bold n\) 同向的话,是正在进入,否则是逃出

    和其他渲染器不同,pbrt 中,\(\omega_i\), \(\omega_o\)\(\bold n\) 可能在表面的相反的边

  3. The local coordinate system used for shading may not be exactly the same as the coordinate system returned by the Shape::Intersect() routines from Chapter 3; they can be modified between intersection and shading to achieve effects like bumping mapping. See Chapter 9 for examples of this kind of modification.

posted @ 2024-09-02 14:31  icewalnut  阅读(7)  评论(0编辑  收藏  举报