Skip to content

Commit 357e04f

Browse files
Merge pull request #25 from MatchaChoco010/include-cos-term-into-bsdf
Include cosine term in BSDF calculations
2 parents 7308f25 + 32fd1db commit 357e04f

18 files changed

+76
-190
lines changed

renderer/src/renderer/base_renderer.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,9 @@ impl<'a, Id: SceneId, F: Filter, T: ToneMap, Strategy: RenderingStrategy>
103103
return None;
104104
}
105105

106-
let cos_theta = material_sample.normal.dot(material_sample.wi).abs();
107106
let sample_wi = material_sample.wi;
108107
let f_value = &material_sample.f;
109-
let throughput_factor = cos_theta / material_sample.pdf;
108+
let throughput_factor = 1.0 / material_sample.pdf;
110109

111110
// wiの方向にレイを飛ばす
112111
let wi_render = &render_to_tangent.inverse() * &sample_wi;

renderer/src/renderer/common.rs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,9 @@ pub fn evaluate_delta_point_light<Id: SceneId>(
4343
let shading_point_tangent = render_to_tangent * shading_point;
4444
let material_result = bsdf.evaluate(lambda, &wo, &wi, &shading_point_tangent);
4545

46-
// Normal mappingされた表面法線に対するcos項
4746
let distance_squared = distance_vector.length_squared();
48-
let cos_theta = material_result.normal.dot(wi).abs();
4947

50-
material_result.f * &intensity.intensity * cos_theta
51-
/ (distance_squared * light_probability)
48+
material_result.f * &intensity.intensity / (distance_squared * light_probability)
5249
} else {
5350
SampledSpectrum::zero()
5451
}
@@ -75,10 +72,7 @@ pub fn evaluate_delta_directional_light<Id: SceneId>(
7572
let shading_point_tangent = render_to_tangent * shading_point;
7673
let material_result = bsdf.evaluate(lambda, &wo, &wi, &shading_point_tangent);
7774

78-
// Normal mappingされた表面法線に対するcos項
79-
let cos_theta = material_result.normal.dot(wi).abs();
80-
81-
material_result.f * &intensity.intensity * cos_theta / light_probability
75+
material_result.f * &intensity.intensity / light_probability
8276
} else {
8377
SampledSpectrum::zero()
8478
}
@@ -113,12 +107,11 @@ pub fn evaluate_area_light<Id: SceneId>(
113107
let material_result =
114108
bsdf.evaluate(lambda, &wo_tangent, &wi_tangent, &shading_point_tangent);
115109

116-
// 幾何項の計算
110+
// 幾何項の計算(シェーディングポイント側のコサイン項はBSDFに含まれるため別途計算不要)
117111
let distance2 = distance_vector.length_squared();
118112
let light_normal = render_to_tangent * radiance.light_normal; // VertexNormalTangent座標系に変換
119-
let cos_material = material_result.normal.dot(wi_tangent).abs(); // VertexNormalTangent座標系で統一
120113
let cos_light = light_normal.dot(-wi_tangent).abs(); // VertexNormalTangent座標系で統一
121-
let g = cos_material * cos_light / distance2;
114+
let g = cos_light / distance2;
122115

123116
material_result.f * &radiance.radiance * g / (pdf * light_probability)
124117
} else {
@@ -153,12 +146,11 @@ pub fn evaluate_area_light_with_mis<Id: SceneId>(
153146
let pdf = radiance.pdf;
154147
let material_result = bsdf.evaluate(lambda, &wo, &wi, &shading_point_tangent);
155148

156-
// 幾何項の計算
149+
// 幾何項の計算(シェーディングポイント側のコサイン項はBSDFに含まれるため別途計算不要)
157150
let distance2 = distance_vector.length_squared();
158151
let light_normal = render_to_tangent * radiance.light_normal;
159-
let cos_material = material_result.normal.dot(wi).abs();
160152
let cos_light = light_normal.dot(-wi).abs();
161-
let g = cos_material * cos_light / distance2;
153+
let g = cos_light / distance2;
162154

163155
// MISのウエイトを計算
164156
let pdf_light_dir = radiance.pdf_dir;
@@ -200,9 +192,7 @@ pub fn evaluate_infinite_light<Id: SceneId>(
200192
let shading_point_tangent = render_to_tangent * shading_point;
201193
let material_result = bsdf.evaluate(lambda, &wo, &wi, &shading_point_tangent);
202194

203-
let cos_theta = material_result.normal.dot(wi).abs();
204-
205-
material_result.f * &radiance_sample.radiance * cos_theta
195+
material_result.f * &radiance_sample.radiance
206196
/ (radiance_sample.pdf_dir * light_probability)
207197
} else {
208198
SampledSpectrum::zero()
@@ -231,14 +221,12 @@ pub fn evaluate_infinite_light_with_mis<Id: SceneId>(
231221
let shading_point_tangent = render_to_tangent * shading_point;
232222
let material_result = bsdf.evaluate(lambda, &wo, &wi, &shading_point_tangent);
233223

234-
let cos_theta = material_result.normal.dot(wi).abs();
235-
236224
let pdf_light_dir = radiance_sample.pdf_dir;
237225
let pdf_bsdf_dir = bsdf.pdf(lambda, &wo, &wi, &shading_point_tangent);
238226
let mis_weight = balance_heuristic(pdf_light_dir, pdf_bsdf_dir);
239227

240-
let contribution = material_result.f * &radiance_sample.radiance * cos_theta
241-
/ (pdf_light_dir * light_probability);
228+
let contribution =
229+
material_result.f * &radiance_sample.radiance / (pdf_light_dir * light_probability);
242230

243231
NeeResult {
244232
contribution,

renderer/src/renderer/mis_renderer.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,7 @@ impl RenderingStrategy for MisStrategy {
223223
let mis_weight = balance_heuristic(bsdf_pdf, light_pdf);
224224

225225
// BSDF項を計算
226-
let cos_theta = material_sample.normal.dot(material_sample.wi).abs();
227-
let throughput_factor = cos_theta / material_sample.pdf;
226+
let throughput_factor = 1.0 / material_sample.pdf;
228227

229228
*sample_contribution +=
230229
throughput * &material_sample.f * radiance * throughput_factor * mis_weight;

renderer/src/renderer/normal_renderer.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use color::{ColorSrgb, tone_map};
44
use scene::{Intersection, SceneId};
5-
use spectrum::SampledWavelengths;
65

76
use crate::{
87
filter::Filter,
@@ -41,27 +40,16 @@ impl<'a, Id: SceneId, F: Filter> Renderer for NormalRenderer<'a, Id, F> {
4140
let uv = sampler.get_2d_pixel();
4241
let rs = camera.sample_ray(p, uv);
4342

44-
// dummyのlambda
45-
let u = sampler.get_1d();
46-
let mut lambda = SampledWavelengths::new_uniform(u);
47-
4843
let intersect = scene.intersect(&rs.ray, f32::MAX);
4944

5045
let color = match intersect {
5146
Some(intersect) => {
52-
let Intersection {
53-
interaction, wo, ..
54-
} = intersect;
47+
let Intersection { interaction, .. } = intersect;
5548
let render_to_tangent = interaction.shading_transform();
56-
let wo = &render_to_tangent * wo;
5749
let shading_point = &render_to_tangent * &interaction;
5850

59-
if let Some(bsdf) = interaction.material.as_bsdf_material() {
60-
let uc = sampler.get_1d();
61-
let uv = sampler.get_2d();
62-
let material_sample = bsdf.sample(uc, uv, &mut lambda, &wo, &shading_point);
63-
let normal = material_sample.normal;
64-
let normal = render_to_tangent.inverse() * normal;
51+
if let Some(_bsdf) = interaction.material.as_bsdf_material() {
52+
let normal = shading_point.shading_normal;
6553
glam::Vec3::new(
6654
normal.x() * 0.5 + 0.5,
6755
normal.y() * 0.5 + 0.5,

renderer/src/renderer/pt_renderer.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ impl RenderingStrategy for PtStrategy {
7878

7979
// 無限光源の放射輝度をBSDFで重み付けして計算
8080
let radiance = scene.evaluate_infinite_light_radiance(&background_ray, lambda);
81-
let cos_theta = material_sample.normal.dot(material_sample.wi).abs();
82-
*sample_contribution +=
83-
throughput * &material_sample.f * radiance * cos_theta / material_sample.pdf;
81+
*sample_contribution += throughput * &material_sample.f * radiance / material_sample.pdf;
8482
}
8583
}
8684

renderer/tests/regression_test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ fn regression_test_scene7_pt_random() {
349349
7,
350350
"pt",
351351
"random",
352-
512,
352+
1024,
353353
"output.test_scene7_pt_random.png",
354354
"test_references/reference_scene7_pt_random.png",
355355
0.05,
@@ -362,7 +362,7 @@ fn regression_test_scene7_pt_sobol() {
362362
7,
363363
"pt",
364364
"sobol",
365-
512,
365+
1024,
366366
"output.test_scene7_pt_sobol.png",
367367
"test_references/reference_scene7_pt_sobol.png",
368368
0.05,

scene/src/material/bsdf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub enum ScatterMode {
4242
// Bsdfのサンプリング結果を表す構造体。
4343
#[derive(Debug, Clone)]
4444
pub struct BsdfSample {
45-
/// BSDF値
45+
/// BSDF値(コサイン項込み)
4646
pub f: spectrum::SampledSpectrum,
4747
/// サンプルされた入射方向(ノーマルマップ接空間)
4848
pub wi: math::Vector3<ShadingNormalTangent>,

scene/src/material/bsdf/conductor.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ impl ConductorBsdf {
283283
// Fresnel反射率を計算
284284
let fresnel = fresnel_complex(wi_cos_n.abs(), &self.eta, &self.k);
285285

286-
// BSDF値: F / |cos(theta_i)|
287-
let f = fresnel / wi_cos_n.abs();
286+
// BSDF値: F (Specularではcosine項の操作なし)
287+
let f = fresnel;
288288

289289
Some(BsdfSample::new(
290290
f,
@@ -346,8 +346,8 @@ impl ConductorBsdf {
346346
// マスキング・シャドウイング項: G(ωo, ωi)
347347
let masking_shadowing = self.masking_shadowing_g(wo, wi);
348348

349-
// Torrance-Sparrow BRDF: D(ωm) * F(ωo·ωm) * G(ωo, ωi) / (4 * cos θi * cos θo)
350-
fresnel * distribution * masking_shadowing / (4.0 * cos_theta_i * cos_theta_o)
349+
// Torrance-Sparrow BRDF(cosine項を含む): D(ωm) * F(ωo·ωm) * G(ωo, ωi) / (4 * cos θo)
350+
fresnel * distribution * masking_shadowing / (4.0 * cos_theta_o)
351351
}
352352

353353
/// BSDF値を評価する。

scene/src/material/bsdf/dielectric.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,10 @@ impl DielectricBsdf {
312312
}
313313
let pdf = self.visible_normal_distribution(wo, wm) / (4.0 * cos_theta_dot) * prob;
314314

315-
// BRDF値計算
315+
// BRDF値計算(cosine項を含む)
316316
let d = self.microfacet_distribution(wm);
317317
let g = self.masking_shadowing_g(wo, &wi);
318-
let f_value = fresnel * d * g / (4.0 * abs_cos_theta(&wi) * abs_cos_theta(wo));
318+
let f_value = fresnel * d * g * abs_cos_theta(&wi) / (4.0 * abs_cos_theta(wo));
319319

320320
Some(BsdfSample::new(
321321
f_value,
@@ -349,11 +349,10 @@ impl DielectricBsdf {
349349

350350
let d = self.microfacet_distribution(wm);
351351
let g = self.masking_shadowing_g(wo, &wi);
352-
let cos_theta_i = abs_cos_theta(&wi);
353352
let cos_theta_o = abs_cos_theta(wo);
354353

355354
let ft = transmission * d * g * wi.dot(wm).abs() * wo.dot(wm).abs()
356-
/ (denom * cos_theta_i * cos_theta_o * etap * etap);
355+
/ (denom * cos_theta_o * etap * etap);
357356

358357
Some(BsdfSample::new(
359358
ft,
@@ -379,8 +378,7 @@ impl DielectricBsdf {
379378
let pdf = prob;
380379

381380
// BTDF値(thin surfaceの特別な処理)
382-
let wi_cos_n = abs_cos_theta(&wi);
383-
let f_value = transmission / wi_cos_n;
381+
let f_value = transmission;
384382

385383
Some(BsdfSample::new(
386384
f_value,
@@ -453,7 +451,7 @@ impl DielectricBsdf {
453451
if wo_cos_n.abs() < 1e-6 {
454452
return None;
455453
}
456-
let f = fresnel / wo_cos_n.abs();
454+
let f = fresnel;
457455
Some(BsdfSample::new(
458456
f,
459457
wi,
@@ -470,7 +468,7 @@ impl DielectricBsdf {
470468

471469
// Thin surfaceの場合、放射輝度のスケーリングは不要(同じ媒質に戻るため)
472470
let transmission = SampledSpectrum::one() - fresnel;
473-
let f = transmission / wi_cos_n.abs();
471+
let f = transmission;
474472
Some(BsdfSample::new(
475473
f,
476474
wi,
@@ -490,7 +488,7 @@ impl DielectricBsdf {
490488
if wo_cos_n.abs() < 1e-6 {
491489
return None;
492490
}
493-
let f = fresnel / wo_cos_n.abs();
491+
let f = fresnel;
494492
Some(BsdfSample::new(
495493
f,
496494
wi,
@@ -510,7 +508,7 @@ impl DielectricBsdf {
510508
}
511509

512510
let transmission = SampledSpectrum::one() - fresnel;
513-
let f = transmission / (etap_scalar.powi(2) * wt_cos_n.abs());
511+
let f = transmission / etap_scalar.powi(2);
514512
Some(BsdfSample::new(
515513
f,
516514
wt,
@@ -588,15 +586,15 @@ impl DielectricBsdf {
588586
let d = self.microfacet_distribution(&wm);
589587
let g = self.masking_shadowing_g(wo, wi);
590588

591-
fresnel * d * g / (4.0 * abs_cos_theta(wi) * abs_cos_theta(wo))
589+
fresnel * d * g / (4.0 * abs_cos_theta(wo))
592590
} else {
593591
let denom = (wi.dot(wm) + wo.dot(wm) / eta_scalar).powi(2);
594592
let d = self.microfacet_distribution(&wm);
595593
let g = self.masking_shadowing_g(wo, wi);
596594
let transmission = SampledSpectrum::one() - fresnel;
597595

598596
transmission * d * g * wi.dot(wm).abs() * wo.dot(wm).abs()
599-
/ (denom * abs_cos_theta(wi) * abs_cos_theta(wo) * eta_scalar * eta_scalar)
597+
/ (denom * abs_cos_theta(wo) * eta_scalar * eta_scalar)
600598
}
601599
}
602600

0 commit comments

Comments
 (0)