// 視点から光源に向けて経路を生成する.
void Scene::BuildImportanceDrivenTheEyePath(
    __in float_t const x, __in float_t const y,
    __inout std::vector<PathVertex> &theEyePathVertices,
    __inout IPrimarySample &sample) const {
    // 初期光線の設定
    {
        camera_.GetPrimaryRayDirection(x, y,
                                       &(theEyePathVertices[1].vIncomingDirection));

        theEyePathVertices[1].power = 1;
        theEyePathVertices[1].fIncomingCosThetaShading =
            hi::dot(theEyePathVertices[1].vIncomingDirection,
                    theEyePathVertices[1].vShadingNormal);
        theEyePathVertices[1].fOutgoingCosThetaGeometric = 1;  // NOTE: 仮の値
        theEyePathVertices[1].fSamplingPrev =
            camera_.GetConstFactor() /
            hi::fourth_power_of(theEyePathVertices[1].fIncomingCosThetaShading);
        theEyePathVertices[1].fSamplingNext = 1;     // NOTE: 仮の値
        theEyePathVertices[1].fGeometricFactor = 1;  // NOTE: 仮の値
        theEyePathVertices[1].fBSDFxIPDF = 1;
    }

    for (std::size_t t = 1;;)  // 再帰的に光線を追跡(末尾再帰)
    {
        PathVertex const &oldTheEyePathVertex = theEyePathVertices[t];
        PathVertex &newTheEyePathVertex = theEyePathVertices[t + 1];

        // 交差判定
        Intersection param;
        newTheEyePathVertex.pGeometry =
            FindIntersection(oldTheEyePathVertex.vPosition,
                             oldTheEyePathVertex.vIncomingDirection, &param);
        if (!newTheEyePathVertex.pGeometry) {
            return;
        }

        // 交点の座標とその点の基底ベクトルを計算
        {
            // シェーディング法線を基準に基底ベクトルを計算する.
            newTheEyePathVertex.SetShadingBasis(param);
            newTheEyePathVertex.bBackSide = param.is_back_side();

            // 散乱方向ベクトルをコピーする.
            newTheEyePathVertex.vOutgoingDirection =
                -oldTheEyePathVertex.vIncomingDirection;

            // シェーディング法線の裏から当たった場合は終了する.
            float_t const fOutgoingCosThetaShading =
                hi::dot(newTheEyePathVertex.vOutgoingDirection,
                        newTheEyePathVertex.vShadingNormal);
            if (fOutgoingCosThetaShading <= 0) {
                newTheEyePathVertex.pGeometry = nullptr;
                return;
            }

            // 輸送されたエネルギーをコピーする.
            newTheEyePathVertex.power = oldTheEyePathVertex.power;
            newTheEyePathVertex.power *= oldTheEyePathVertex.fBSDFxIPDF;

            // 交点座標を設定する.
            newTheEyePathVertex.vPosition = oldTheEyePathVertex.vIncomingDirection;
            newTheEyePathVertex.vPosition *= param.t_max();
            newTheEyePathVertex.vPosition += oldTheEyePathVertex.vPosition;

            // 幾何学的法線と散乱方向ベクトルの内積を求める.
            newTheEyePathVertex.fOutgoingCosThetaGeometric =
                hi::dot(newTheEyePathVertex.vOutgoingDirection,
                        newTheEyePathVertex.vGeometricNormal);

            // 幾何学項を計算する.
            newTheEyePathVertex.fGeometricFactor =
                newTheEyePathVertex.fOutgoingCosThetaGeometric *
                oldTheEyePathVertex.fIncomingCosThetaShading /
                hi::square_of(param.t_max());
        }

        Bsdf const *const pBSDF = bsdfs_[newTheEyePathVertex.pGeometry->bsdf()];

        // NOTE: 反射回数の限界数を超えたら打ち切る.
        if (++t >= XYZ_CONFIG_kMaxRandomWalkDepth) {
            theEyePathVertices[t + 1].pGeometry = nullptr;
            return;
        }

        // 光源が直接可視の場合の処理.
        Bsdf::type const theEyePathVertexType = pBSDF->What();
        if (Bsdf::LIGHT == pBSDF->What()) {
            theEyePathVertices[t + 1].pGeometry = nullptr;
            return;
        }

        // 散乱ベクトルの計算
        if ((t > 2) && (Bsdf::LAMBERT == theEyePathVertexType) &&
                (oldTheEyePathVertex.bSpecular))  // デルタ反射後の集光模様を描く
        {
            ImportanceQuery importons(newTheEyePathVertex);
            Scene::GetInstance().ImportonMap().kNN_query(
                newTheEyePathVertex.vPosition, importons);
            if (!pBSDF->CameraToLightsScatteringDirection(&newTheEyePathVertex,
                    importons, sample)) {
                theEyePathVertices[t + 1].pGeometry = nullptr;
                return;
            }
        } else {
            if (!pBSDF->CameraToLightsScatteringDirection(&newTheEyePathVertex,
                    sample)) {
                theEyePathVertices[t + 1].pGeometry = nullptr;
                return;
            }
        }
    }
}
// 視点から光源に向けて経路を生成する.
void Scene::BuildImportanceDrivenTheEyePath(
    __in float_t const x, __in float_t const y,
    __in PathVertex const &theLightsPathVertex,
    __inout std::vector<PathVertex> &theEyePathVertices,
    __inout CIE_XYZ_Color *const pColor, __inout IPrimarySample &sample) const {
  // 初期光線の設定
  {
    camera_.GetPrimaryRayDirection(x, y,
                                   &(theEyePathVertices[1].vIncomingDirection));

    theEyePathVertices[1].power = 1;
    theEyePathVertices[1].fIncomingCosThetaShading =
        hi::dot(theEyePathVertices[1].vIncomingDirection,
                theEyePathVertices[1].vShadingNormal);
    theEyePathVertices[1].fOutgoingCosThetaGeometric = 1;  // NOTE: 仮の値
    theEyePathVertices[1].fSamplingPrev =
        camera_.GetConstFactor() /
        hi::fourth_power_of(theEyePathVertices[1].fIncomingCosThetaShading);
    theEyePathVertices[1].fSamplingNext = 1;     // NOTE: 仮の値
    theEyePathVertices[1].fGeometricFactor = 1;  // NOTE: 仮の値
    theEyePathVertices[1].fBSDFxIPDF = 1;
  }

  for (std::size_t t = 1;;)  // 再帰的に光線を追跡(末尾再帰)
  {
    PathVertex const &oldTheEyePathVertex = theEyePathVertices[t];
    PathVertex &newTheEyePathVertex = theEyePathVertices[t + 1];

    // 交差判定
    Intersection param;
    newTheEyePathVertex.pGeometry =
        FindIntersection(oldTheEyePathVertex.vPosition,
                         oldTheEyePathVertex.vIncomingDirection, &param);
    if (!newTheEyePathVertex.pGeometry) {
      return;
    }

    // 交点の座標とその点の基底ベクトルを計算
    {
      // シェーディング法線を基準に基底ベクトルを計算する.
      newTheEyePathVertex.SetShadingBasis(param);
      newTheEyePathVertex.bBackSide = param.is_back_side();

      // 散乱方向ベクトルをコピーする.
      newTheEyePathVertex.vOutgoingDirection =
          -oldTheEyePathVertex.vIncomingDirection;

      // シェーディング法線の裏から当たった場合は終了する.
      float_t const fOutgoingCosThetaShading =
          hi::dot(newTheEyePathVertex.vOutgoingDirection,
                  newTheEyePathVertex.vShadingNormal);
      if (fOutgoingCosThetaShading <= 0) {
        newTheEyePathVertex.pGeometry = hi::nullptr;
        return;
      }

      // 輸送されたエネルギーをコピーする.
      newTheEyePathVertex.power = oldTheEyePathVertex.power;
      newTheEyePathVertex.power *= oldTheEyePathVertex.fBSDFxIPDF;

      // 交点座標を設定する.
      newTheEyePathVertex.vPosition = oldTheEyePathVertex.vIncomingDirection;
      newTheEyePathVertex.vPosition *= param.t_max();
      newTheEyePathVertex.vPosition += oldTheEyePathVertex.vPosition;

      // 幾何学的法線と散乱方向ベクトルの内積を求める.
      newTheEyePathVertex.fOutgoingCosThetaGeometric =
          hi::dot(newTheEyePathVertex.vOutgoingDirection,
                  newTheEyePathVertex.vGeometricNormal);

      // 幾何学項を計算する.
      newTheEyePathVertex.fGeometricFactor =
          newTheEyePathVertex.fOutgoingCosThetaGeometric *
          oldTheEyePathVertex.fIncomingCosThetaShading /
          hi::square_of(param.t_max());
    }

    Bsdf const *const pBSDF = bsdfs_[newTheEyePathVertex.pGeometry->bsdf()];

    // 光源が直接可視の場合の処理.
    if (Bsdf::LIGHT == pBSDF->What()) {
      if (!newTheEyePathVertex.bBackSide) {
        // 経路長がs+t-1(ただしs=0)の経路を生成
        float_t wst = 1;

        if (t > 2) {
          // 光源部分経路を延長していく場合の経路密度を計算する.
          // 光源に衝突すると経路が終了するので上書きしてよい.
          theEyePathVertices[t + 1].fSamplingNext =
              hi::rcp(GetLightArea());                 // P_{A}(x_{1})
          newTheEyePathVertex.fSamplingPrev = 1;       // NOTE: 常に1
          newTheEyePathVertex.fSamplingNext = M_1_PI;  // 平面光源なので
          {
            float_t pst = 1;
            for (std::size_t i = t; i > 1; --i) {
              pst *= theEyePathVertices[i + 1].fSamplingNext /
                     theEyePathVertices[i - 1].fSamplingPrev;

              if (!theEyePathVertices[i].bSpecular &&
                  !theEyePathVertices[i - 1].bSpecular) {
                wst +=
                    hi::square_of(pst / theEyePathVertices[i].fGeometricFactor);
              }
            }
          }
          wst = hi::rcp(wst);
        }

        (*pColor) +=
            theLightsPathVertex.power * newTheEyePathVertex.power *
            (wst * M_1_PI *
             hi::rcp(GetLightArea()));  // NOTE: ランバート反射面のみ扱う.
      }
      newTheEyePathVertex.pGeometry = hi::nullptr;
      return;
    }

    // NOTE: 反射回数の限界数を超えたら打ち切る.
    if (++t >= XYZRENDERER_CONFIG_kMaxRandomWalkDepth) {
      theEyePathVertices[t + 1].pGeometry = hi::nullptr;
      return;
    }