// 視点から光源に向けて経路を生成する. 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, ¶m); 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, ¶m); 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; }