Added gpu config flag, completed light sampling methods
This commit is contained in:
parent
2448ab890e
commit
0fcfcbd467
18 changed files with 110 additions and 60 deletions
|
|
@ -2,4 +2,13 @@ fn main() {
|
|||
// This allows "spirv" to be used in #[cfg(target_arch = "...")]
|
||||
// without triggering a warning.
|
||||
println!("cargo:rustc-check-cfg=cfg(target_arch, values(\"spirv\"))");
|
||||
|
||||
// `gpu` is set for every device backend, so host-only code can be gated once
|
||||
// as #[cfg(not(gpu))] instead of naming each target. Adding a backend means
|
||||
// editing this line, not 30-odd cfg attributes.
|
||||
println!("cargo::rustc-check-cfg=cfg(gpu)");
|
||||
let target = std::env::var("TARGET").unwrap_or_default();
|
||||
if target.contains("spirv") || target.contains("cuda") {
|
||||
println!("cargo::rustc-cfg=gpu");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub struct OrthographicCamera {
|
|||
pub dy_camera: Vector3f,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
impl OrthographicCamera {
|
||||
pub fn new(
|
||||
base: CameraBase,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub struct PerspectiveCamera {
|
|||
pub cos_total_width: Float,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
impl PerspectiveCamera {
|
||||
pub fn new(
|
||||
base: CameraBase,
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ pub trait CameraTrait {
|
|||
fn generate_ray(&self, sample: CameraSample, lambda: &SampledWavelengths) -> Option<CameraRay>;
|
||||
|
||||
fn get_film(&self) -> &Film {
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
{
|
||||
if self.base().film.is_null() {
|
||||
panic!(
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ impl RGBFilm {
|
|||
}
|
||||
|
||||
pub fn get_sensor(&self) -> &PixelSensor {
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
{
|
||||
if self.base.sensor.is_null() {
|
||||
panic!(
|
||||
|
|
@ -203,7 +203,7 @@ impl RGBFilm {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(target_os = "cuda", derive(Copy))]
|
||||
#[cfg_attr(gpu, derive(Copy))]
|
||||
pub struct GBufferPixel {
|
||||
pub rgb_sum: [AtomicFloat; 3],
|
||||
pub weight_sum: AtomicFloat,
|
||||
|
|
@ -240,7 +240,7 @@ impl Default for GBufferPixel {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(target_os = "cuda", derive(Copy))]
|
||||
#[cfg_attr(gpu, derive(Copy))]
|
||||
pub struct GBufferFilm {
|
||||
pub base: FilmBase,
|
||||
pub output_from_render: AnimatedTransform,
|
||||
|
|
@ -294,7 +294,7 @@ impl GBufferFilm {
|
|||
}
|
||||
|
||||
pub fn get_sensor(&self) -> &PixelSensor {
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
{
|
||||
if self.base.sensor.is_null() {
|
||||
panic!(
|
||||
|
|
@ -387,7 +387,7 @@ impl GBufferFilm {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(target_os = "cuda", derive(Copy))]
|
||||
#[cfg_attr(gpu, derive(Copy))]
|
||||
pub struct SpectralPixel {
|
||||
pub rgb_sum: [AtomicFloat; 3],
|
||||
pub rgb_weight_sum: AtomicFloat,
|
||||
|
|
@ -419,7 +419,7 @@ impl Default for SpectralPixel {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(target_os = "cuda", derive(Copy, Clone))]
|
||||
#[cfg_attr(gpu, derive(Copy, Clone))]
|
||||
pub struct SpectralFilm {
|
||||
pub base: FilmBase,
|
||||
pub lambda_min: Float,
|
||||
|
|
@ -609,7 +609,7 @@ pub struct FilmBase {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(target_os = "cuda", derive(Copy, Clone))]
|
||||
#[cfg_attr(gpu, derive(Copy, Clone))]
|
||||
pub enum Film {
|
||||
RGB(RGBFilm),
|
||||
GBuffer(GBufferFilm),
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ impl SurfaceInteraction {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
pub fn set_intersection_properties(
|
||||
&mut self,
|
||||
mtl: MaterialIdx,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub struct LightLiSample {
|
|||
pub p_light: Interaction,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
impl LightLiSample {
|
||||
pub fn new(l: SampledSpectrum, wi: Vector3f, pdf: Float, p_light: Interaction) -> Self {
|
||||
Self {
|
||||
|
|
@ -188,7 +188,7 @@ pub struct LightBounds {
|
|||
pub two_sided: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
impl LightBounds {
|
||||
pub fn new(
|
||||
bounds: &Bounds3f,
|
||||
|
|
@ -327,13 +327,13 @@ pub trait LightTrait {
|
|||
self.base().light_type
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn bounds(&self) -> Option<LightBounds>;
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn preprocess(&mut self, scene_bounds: &Bounds3f);
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ pub struct MajorantGrid {
|
|||
|
||||
|
||||
impl MajorantGrid {
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
pub fn new(bounds: Bounds3f, res: Point3i) -> Self {
|
||||
let n_voxels = (res.x() * res.y() * res.z()) as usize;
|
||||
let voxels = gvec_with_capacity(n_voxels);
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ pub struct PointTransformMapping {
|
|||
}
|
||||
|
||||
impl PointTransformMapping {
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
pub fn new(texture_from_render: Transform) -> Self {
|
||||
Self {
|
||||
texture_from_render,
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ impl LightTrait for DiffuseAreaLight {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
let mut l = SampledSpectrum::new(0.);
|
||||
if !self.image.is_null() {
|
||||
|
|
@ -153,10 +153,10 @@ impl LightTrait for DiffuseAreaLight {
|
|||
PI * two_side * self.area * l
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn preprocess(&mut self, _scene_bounds: &Bounds3f) {}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn bounds(&self) -> Option<LightBounds> {
|
||||
let mut phi = 0.;
|
||||
if !self.image.is_null() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
use crate::core::geometry::{Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f};
|
||||
use crate::core::geometry::{
|
||||
Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f, VectorLike,
|
||||
};
|
||||
use crate::core::image::Image;
|
||||
use crate::core::interaction::{Interaction, InteractionBase, SimpleInteraction};
|
||||
use crate::core::light::{
|
||||
LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait, LightType,
|
||||
};
|
||||
|
|
@ -34,12 +37,20 @@ impl LightTrait for GoniometricLight {
|
|||
|
||||
fn sample_li(
|
||||
&self,
|
||||
_ctx: &LightSampleContext,
|
||||
ctx: &LightSampleContext,
|
||||
_u: Point2f,
|
||||
_lambda: &SampledWavelengths,
|
||||
lambda: &SampledWavelengths,
|
||||
_allow_incomplete_pdf: bool,
|
||||
) -> Option<LightLiSample> {
|
||||
todo!()
|
||||
let render_from_light = self.base().render_from_light;
|
||||
let p = render_from_light.apply_to_point(Point3f::new(0., 0., 0.));
|
||||
let wi = (p - ctx.p()).normalize();
|
||||
let wl = render_from_light.apply_inverse_vector(-wi);
|
||||
let li = self.i(wl, lambda) / p.distance_squared(ctx.p());
|
||||
let base = InteractionBase::new_boundary(p, 0., self.base.medium_interface);
|
||||
let intr = SimpleInteraction::new(base);
|
||||
|
||||
Some(LightLiSample::new(li, wi, 1., Interaction::Simple(intr)))
|
||||
}
|
||||
|
||||
fn pdf_li(
|
||||
|
|
@ -76,7 +87,7 @@ impl LightTrait for GoniometricLight {
|
|||
))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
let resolution = self.image.resolution();
|
||||
let mut sum_y = 0.;
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ impl LightTrait for UniformInfiniteLight {
|
|||
None
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
4. * PI * PI * square(self.scene_radius) * self.scale * self.lemit.sample(&lambda)
|
||||
}
|
||||
|
|
@ -227,21 +227,17 @@ impl LightTrait for ImageInfiniteLight {
|
|||
self.image_le(uv, lambda)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
let mut sum_l = SampledSpectrum::new(0.);
|
||||
let width = self.image.resolution().x();
|
||||
let height = self.image.resolution().y();
|
||||
for v in 0..height {
|
||||
for u in 0..width {
|
||||
let mut rgb = RGB::default();
|
||||
for c in 0..3 {
|
||||
rgb[c] = self.image.get_channel_with_wrap(
|
||||
let rgb = RGB::from(self.image.get_channels_with_wrap::<3>(
|
||||
Point2i::new(u, v),
|
||||
c,
|
||||
WrapMode::OctahedralSphere.into(),
|
||||
);
|
||||
}
|
||||
));
|
||||
sum_l += RGBIlluminantSpectrum::new(&self.image_color_space, rgb.clamp_zero())
|
||||
.sample(&lambda);
|
||||
}
|
||||
|
|
@ -341,7 +337,7 @@ impl PortalInfiniteLight {
|
|||
(self.portal[1] - self.portal[0]).norm() * (self.portal[3] - self.portal[0]).norm()
|
||||
}
|
||||
|
||||
pub fn render_from_image(portal_frame: Frame, uv: Point2f) -> (Vector3f, Float) {
|
||||
pub fn render_from_image_with(portal_frame: Frame, uv: Point2f) -> (Vector3f, Float) {
|
||||
let alpha = -PI / 2.0 + uv.x() * PI;
|
||||
let beta = -PI / 2.0 + uv.y() * PI;
|
||||
|
||||
|
|
@ -354,6 +350,11 @@ impl PortalInfiniteLight {
|
|||
|
||||
(portal_frame.from_local(w), duv_dw)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn render_from_image(&self, uv: Point2f) -> (Vector3f, Float) {
|
||||
Self::render_from_image_with(self.portal_frame, uv)
|
||||
}
|
||||
}
|
||||
|
||||
impl LightTrait for PortalInfiniteLight {
|
||||
|
|
@ -370,7 +371,7 @@ impl LightTrait for PortalInfiniteLight {
|
|||
) -> Option<LightLiSample> {
|
||||
let b = self.image_bounds(ctx.p())?;
|
||||
let (uv, map_pdf) = self.distribution.sample(u, b)?;
|
||||
let (wi, duv_dw) = Self::render_from_image(self.portal_frame, uv);
|
||||
let (wi, duv_dw) = self.render_from_image(uv);
|
||||
if duv_dw == 0. {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -403,17 +404,34 @@ impl LightTrait for PortalInfiniteLight {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
fn phi(&self, _lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
todo!()
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
let mut sum_l = SampledSpectrum::new(0.);
|
||||
let width = self.image.resolution().x();
|
||||
let height = self.image.resolution().y();
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let rgb = RGB::from(self.image.get_channels::<3>(Point2i::new(x, y)));
|
||||
let st = Point2f::new(
|
||||
(x as Float + 0.5) / width as Float,
|
||||
(y as Float + 0.5) / height as Float,
|
||||
);
|
||||
let (_, duv_dw) = self.render_from_image(st);
|
||||
sum_l += RGBIlluminantSpectrum::new(&self.image_color_space, rgb.clamp_zero())
|
||||
.sample(&lambda)
|
||||
/ duv_dw;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
self.scale * self.area() * sum_l / (width * height) as Float
|
||||
}
|
||||
|
||||
#[cfg(not(gpu))]
|
||||
fn preprocess(&mut self, scene_bounds: &Bounds3f) {
|
||||
(self.scene_center, self.scene_radius) = scene_bounds.bounding_sphere();
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn bounds(&self) -> Option<LightBounds> {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,14 +51,14 @@ impl LightTrait for PointLight {
|
|||
0.
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
4. * PI * self.scale * self.i.sample(&lambda)
|
||||
}
|
||||
|
||||
fn preprocess(&mut self, _scene_bounds: &Bounds3f) {}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn bounds(&self) -> Option<LightBounds> {
|
||||
let p = self
|
||||
.base
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::core::geometry::{
|
|||
Bounds2f, Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f, VectorLike, cos_theta,
|
||||
};
|
||||
use crate::core::image::Image;
|
||||
use crate::core::interaction::{Interaction, InteractionBase, SimpleInteraction};
|
||||
use crate::core::light::{
|
||||
LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait, LightType,
|
||||
};
|
||||
|
|
@ -33,7 +34,7 @@ pub struct ProjectionLight {
|
|||
}
|
||||
|
||||
impl ProjectionLight {
|
||||
pub fn i(&self, w: Vector3f, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
pub fn i(&self, w: Vector3f, lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||
if w.z() < self.hither {
|
||||
return SampledSpectrum::new(0.);
|
||||
}
|
||||
|
|
@ -44,10 +45,10 @@ impl ProjectionLight {
|
|||
let uv = Point2f::from(self.screen_bounds.offset(&Point2f::new(ps.x(), ps.y())));
|
||||
let mut rgb = RGB::default();
|
||||
for c in 0..3 {
|
||||
rgb[c] = self.image.lookup_nearest_channel(uv, c as i32);
|
||||
rgb[c] = self.image.lookup_nearest_channel(uv, c);
|
||||
}
|
||||
let s = RGBIlluminantSpectrum::new(&*self.image_color_space, rgb.clamp_zero());
|
||||
self.scale * s.sample(&lambda)
|
||||
let s = RGBIlluminantSpectrum::new(&self.image_color_space, rgb.clamp_zero());
|
||||
self.scale * s.sample(lambda)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,12 +59,23 @@ impl LightTrait for ProjectionLight {
|
|||
|
||||
fn sample_li(
|
||||
&self,
|
||||
_ctx: &LightSampleContext,
|
||||
ctx: &LightSampleContext,
|
||||
_u: Point2f,
|
||||
_lambda: &SampledWavelengths,
|
||||
lambda: &SampledWavelengths,
|
||||
_allow_incomplete_pdf: bool,
|
||||
) -> Option<LightLiSample> {
|
||||
todo!()
|
||||
let render_from_light = self.base().render_from_light;
|
||||
let p = render_from_light.apply_to_point(Point3f::new(0., 0., 0.));
|
||||
let wi = (p - ctx.p()).normalize();
|
||||
let wl = render_from_light.apply_inverse_vector(-wi);
|
||||
let li = self.i(wl, lambda) / p.distance_squared(ctx.p());
|
||||
if li.is_black() {
|
||||
return None;
|
||||
}
|
||||
let base = InteractionBase::new_boundary(p, 0., self.base.medium_interface);
|
||||
let intr = SimpleInteraction::new(base);
|
||||
|
||||
Some(LightLiSample::new(li, wi, 1., Interaction::Simple(intr)))
|
||||
}
|
||||
|
||||
fn pdf_li(
|
||||
|
|
@ -72,7 +84,7 @@ impl LightTrait for ProjectionLight {
|
|||
_wi: Vector3f,
|
||||
_allow_incomplete_pdf: bool,
|
||||
) -> Float {
|
||||
todo!()
|
||||
0.
|
||||
}
|
||||
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
|
|
@ -93,10 +105,10 @@ impl LightTrait for ProjectionLight {
|
|||
let dwda = cos_theta(w).powi(3);
|
||||
let mut rgb = RGB::default();
|
||||
for c in 0..3 {
|
||||
rgb[c] = self.image.get_channel(Point2i::new(x, y), c as i32);
|
||||
rgb[c] = self.image.get_channel(Point2i::new(x, y), c);
|
||||
}
|
||||
|
||||
let s = RGBIlluminantSpectrum::new(&*self.image_color_space, rgb.clamp_zero());
|
||||
let s = RGBIlluminantSpectrum::new(&self.image_color_space, rgb.clamp_zero());
|
||||
sum += s.sample(&lambda) * dwda;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ impl LightTrait for SpotLight {
|
|||
0.
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
|
||||
self.scale
|
||||
* self.iemit.sample(&lambda)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub struct HairMaterial {
|
|||
}
|
||||
|
||||
impl HairMaterial {
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
sigma_a: Ptr<SpectrumTexture>,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ impl BilinearPatchShape {
|
|||
Some([mesh.n[v0], mesh.n[v1], mesh.n[v2], mesh.n[v3]])
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "cuda"))]
|
||||
#[cfg(not(gpu))]
|
||||
pub fn new(mesh: Ptr<BilinearPatchMesh>, blp_index: i32) -> Self {
|
||||
let mut bp = BilinearPatchShape {
|
||||
mesh,
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ fn create_portal_light(
|
|||
|
||||
// Build distribution
|
||||
let duv_dw = |p: Point2f| -> Float {
|
||||
let (_, jacobian) = PortalInfiniteLight::render_from_image(portal_frame, p);
|
||||
let (_, jacobian) = PortalInfiniteLight::render_from_image_with(portal_frame, p);
|
||||
jacobian
|
||||
};
|
||||
let d = remapped.get_sampling_distribution(
|
||||
|
|
@ -247,7 +247,7 @@ fn remap_image_through_portal(
|
|||
(y as Float + 0.5) / height as Float,
|
||||
);
|
||||
|
||||
let (w_world, _) = PortalInfiniteLight::render_from_image(*portal_frame, uv);
|
||||
let (w_world, _) = PortalInfiniteLight::render_from_image_with(*portal_frame, uv);
|
||||
let w_local = render_from_light.apply_inverse_vector(w_world).normalize();
|
||||
let uv_equi = equal_area_sphere_to_square(w_local);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue