Skip to content

Commit 2ea38b3

Browse files
committed
make BSDFVector immutable
1 parent 018ffe8 commit 2ea38b3

File tree

10 files changed

+116
-159
lines changed

10 files changed

+116
-159
lines changed

src/accel/bvh.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ function intersect!(pool, bvh::BVHAccel, ray::MutableRef{<:AbstractRay})
220220
inv_dir = 1f0 ./ ray.d
221221
dir_is_neg = is_dir_negative(ray.d)
222222

223-
to_visit_offset, current_node_i = 1, 1
223+
to_visit_offset::Int32, current_node_i::Int32 = 1, 1
224224
@inbounds nodes_to_visit = bvh.nodes_to_visit[Threads.threadid()]
225225
nodes_to_visit .= 0
226226
@inbounds while true
@@ -230,7 +230,7 @@ function intersect!(pool, bvh::BVHAccel, ray::MutableRef{<:AbstractRay})
230230
# Intersect ray with primitives in node.
231231
for i in 0:ln.n_primitives-1
232232
tmp_primitive = bvh.primitives[ln.primitives_offset+i]
233-
tmp_hit, tmp_interaction = intersect!(
233+
tmp_hit, tmp_interaction = intersect_p!(
234234
pool, tmp_primitive, ray,
235235
)
236236
if tmp_hit && !(tmp_interaction isa Vec3)
@@ -244,7 +244,7 @@ function intersect!(pool, bvh::BVHAccel, ray::MutableRef{<:AbstractRay})
244244
current_node_i = nodes_to_visit[to_visit_offset]
245245
else
246246
if dir_is_neg[ln.split_axis] == 2
247-
nodes_to_visit[to_visit_offset] = current_node_i + 1
247+
nodes_to_visit[to_visit_offset] = current_node_i + Int32(1)
248248
current_node_i = ln.second_child_offset
249249
else
250250
nodes_to_visit[to_visit_offset] = ln.second_child_offset

src/materials/bsdf.jl

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
struct _BXDFVector{S<:Spectrum}
1+
struct BXDFVector{S<:Spectrum}
22
bxdf_1::UberBxDF{S}
33
bxdf_2::UberBxDF{S}
44
bxdf_3::UberBxDF{S}
@@ -10,8 +10,15 @@ struct _BXDFVector{S<:Spectrum}
1010
last::UInt8
1111
end
1212

13-
const BXDFVector{S} = MutableRef{_BXDFVector{S}}
13+
Base.Base.@propagate_inbounds function Base.getindex(b::BXDFVector, i::Int)
14+
i > b.last && error("Out of bounds $(i)")
15+
return getfield(b, i)
16+
end
1417

18+
@inline function BXDFVector{S}(sbdfs::Vararg{UberBxDF{S}, N}) where {S<:Spectrum, N}
19+
missing_bxdf = ntuple(i -> UberBxDF{S}(), 8 - N)
20+
return BXDFVector{S}(sbdfs..., missing_bxdf..., UInt8(N))
21+
end
1522

1623
struct BSDF{S}
1724
"""
@@ -44,20 +51,24 @@ struct BSDF{S}
4451
Individual BxDF components. Maximum allowed number of components is 8.
4552
"""
4653
bxdfs::BXDFVector{S}
54+
end
4755

48-
function BSDF(pool, si::SurfaceInteraction, η::Float32 = 1f0)
49-
ng = si.core.n
50-
ns = si.shading.n
51-
ss = normalize(si.shading.∂p∂u)
52-
ts = ns × ss
53-
bsdfs = allocate(pool, BXDFVector{RGBSpectrum})
54-
bsdfs.last = 0
55-
new{RGBSpectrum}(
56-
η, ng, ns, ss, ts, bsdfs,
57-
)
58-
end
56+
function BSDF(si::SurfaceInteraction, sbdfs::Vararg{UberBxDF{S}, N}) where {S<:Spectrum, N}
57+
BSDF(si, 1f0, sbdfs...)
5958
end
6059

60+
function BSDF(si::SurfaceInteraction, η::Float32, sbdfs::Vararg{UberBxDF{S},N}) where {S<:Spectrum, N}
61+
ng = si.core.n
62+
ns = si.shading.n
63+
ss = normalize(si.shading.∂p∂u)
64+
ts = ns × ss
65+
bsdfs = BXDFVector{RGBSpectrum}(sbdfs...)
66+
BSDF{RGBSpectrum}(
67+
η, ng, ns, ss, ts, bsdfs,
68+
)
69+
end
70+
71+
6172
"""
6273
Given the orthonormal vectors s, t, n in world space, the matrix `M`
6374
that transforms vectors in world space to local reflection space is:
@@ -130,12 +141,14 @@ function sample_f(
130141
bxdf = nothing
131142
bxdfs = b.bxdfs
132143
Base.Cartesian.@nexprs 8 i -> begin
133-
_bxdf = bxdfs[i]
134-
if _bxdf & type
135-
if count == 1
136-
bxdf = _bxdf
144+
if i <= bxdfs.last
145+
_bxdf = bxdfs[i]
146+
if _bxdf & type
147+
if count == 1
148+
bxdf = _bxdf
149+
end
150+
count -= 1
137151
end
138-
count -= 1
139152
end
140153
end
141154
@real_assert bxdf nothing "n bxdfs $(b.n_bxdfs), component $component, count $count"
@@ -173,12 +186,14 @@ function sample_f(
173186
reflect = ((wi_world b.ng) * (wo_world b.ng)) > 0
174187
f = RGBSpectrum(0f0)
175188
Base.Cartesian.@nexprs 8 i -> begin
176-
bxdf = bxdfs[i]
177-
if i <= bxdfs.last && ((bxdf & type) && (
178-
(reflect && (bxdf.type & BSDF_REFLECTION != 0)) ||
179-
(!reflect && (bxdf.type & BSDF_TRANSMISSION != 0))
180-
))
181-
f += bxdf(wo, wi)
189+
if i <= bxdfs.last
190+
bxdf = bxdfs[i]
191+
if ((bxdf & type) && (
192+
(reflect && (bxdf.type & BSDF_REFLECTION != 0)) ||
193+
(!reflect && (bxdf.type & BSDF_TRANSMISSION != 0))
194+
))
195+
f += bxdf(wo, wi)
196+
end
182197
end
183198
end
184199
end

src/materials/material.jl

Lines changed: 19 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,11 @@ Compute scattering function.
1313
Base.Base.@propagate_inbounds function matte_material(pool, m::UberMaterial, si::SurfaceInteraction, ::Bool, transport)
1414
# TODO perform bump mapping
1515
# Evaluate textures and create BSDF.
16-
bsdf = BSDF(pool, si)
1716
r = clamp(m.Kd(si))
1817
is_black(r) && return
1918
σ = clamp(m.σ(si), 0f0, 90f0)
20-
bsdfs = bsdf.bxdfs
21-
if σ 0f0
22-
bsdfs[1] = LambertianReflection(r)
23-
else
24-
bsdfs[1] = OrenNayar(r, σ)
25-
end
26-
bsdfs.last = 1
27-
return bsdf
19+
lambertian = 0.0f0)
20+
return BSDF(si, LambertianReflection(lambertian, r), OrenNayar(!lambertian, r, σ))
2821
end
2922

3023
const MIRROR_MATERIAL = UInt8(2)
@@ -34,13 +27,9 @@ function MirrorMaterial(Kr::Texture)
3427
end
3528

3629
Base.Base.@propagate_inbounds function mirror_material(pool, m::UberMaterial, si::SurfaceInteraction, ::Bool, transport)
37-
bsdf = BSDF(pool, si)
3830
r = clamp(m.Kr(si))
3931
is_black(r) && return
40-
bxdfs = bsdf.bxdfs
41-
bxdfs[1] = SpecularReflection(r, FresnelNoOp())
42-
bxdfs.last = 1
43-
return bsdf
32+
return BSDF(si, SpecularReflection(!is_black(r), r, FresnelNoOp()))
4433
end
4534

4635
const GLASS_MATERIAL = UInt8(3)
@@ -58,17 +47,15 @@ Base.Base.@propagate_inbounds function glass_material(pool, g::UberMaterial, si:
5847
u_roughness = g.u_roughness(si)
5948
v_roughness = g.v_roughness(si)
6049

61-
bsdf = BSDF(pool, si, η)
62-
bsdfs = bsdf.bxdfs
6350
r = clamp(g.Kr(si))
6451
t = clamp(g.Kt(si))
65-
is_black(r) && is_black(t) && return
52+
r_black = is_black(r)
53+
t_black = is_black(t)
54+
r_black && t_black && return BSDF(pool, si, η)
6655

6756
is_specular = u_roughness 0 && v_roughness 0
6857
if is_specular && allow_multiple_lobes
69-
bsdfs[1] = FresnelSpecular(r, t, 1.0f0, η, transport)
70-
bsdfs.last = 1
71-
return
58+
return BSDF(si, η, FresnelSpecular(true, r, t, 1.0f0, η, transport))
7259
end
7360

7461
if g.remap_roughness
@@ -78,26 +65,14 @@ Base.Base.@propagate_inbounds function glass_material(pool, g::UberMaterial, si:
7865
distribution = is_specular ? nothing : TrowbridgeReitzDistribution(
7966
u_roughness, v_roughness,
8067
)
81-
last = 0
82-
if !is_black(r)
83-
fresnel = FresnelDielectric(1f0, η)
84-
if is_specular
85-
bsdfs[1] = SpecularReflection(r, fresnel)
86-
else
87-
bsdfs[1] = MicrofacetReflection(r, distribution, fresnel, transport)
88-
end
89-
last = 1
90-
end
91-
if !is_black(t)
92-
last += 1
93-
if is_specular
94-
bsdfs[last] = SpecularTransmission(t, 1.0f0, η, transport)
95-
else
96-
bsdfs[last] = MicrofacetTransmission(t, distribution, 1.0f0, η, transport)
97-
end
98-
end
99-
bsdfs.last = last
100-
return bsdf
68+
fresnel = FresnelDielectric(1f0, η)
69+
return BSDF(
70+
si, η,
71+
SpecularReflection(!r_black && is_specular, r, fresnel),
72+
MicrofacetReflection(!r_black && !is_specular, r, distribution, fresnel, transport),
73+
SpecularTransmission(!t_black && is_specular, t, 1.0f0, η, transport),
74+
MicrofacetTransmission(!t_black && !is_specular, t, distribution, 1.0f0, η, transport)
75+
)
10176
end
10277

10378
const PLASTIC_MATERIAL = UInt8(4)
@@ -111,25 +86,17 @@ end
11186
Base.Base.@propagate_inbounds function plastic_material(pool, p::UberMaterial,
11287
si::SurfaceInteraction, ::Bool, transport,
11388
)
114-
bsdf = BSDF(pool, si)
115-
bsdfs = bsdf.bxdfs
11689
# Initialize diffuse componen of plastic material.
11790
kd = clamp(p.Kd(si))
118-
last = 0
119-
if !is_black(kd)
120-
bsdfs[1] = LambertianReflection(kd)
121-
last += 1
122-
end
91+
bsdf_1 = LambertianReflection(!is_black(kd), kd)
12392
# Initialize specular component.
12493
ks = clamp(p.Ks(si))
125-
is_black(ks) && return
94+
is_black(ks) && return BSDF(si, bsdf_1)
12695
# Create microfacet distribution for plastic material.
12796
fresnel = FresnelDielectric(1.5f0, 1f0)
12897
rough = p.roughness(si)
12998
p.remap_roughness && (rough = roughness_to_α(rough))
13099
distribution = TrowbridgeReitzDistribution(rough, rough)
131-
last += 1
132-
bsdfs[last] = MicrofacetReflection(ks, distribution, fresnel, transport)
133-
bsdfs.last = last
134-
return bsdf
100+
bsdf_2 = MicrofacetReflection(true, ks, distribution, fresnel, transport)
101+
return BSDF(si, bsdf_1, bsdf_2)
135102
end

src/materials/uber-material.jl

Lines changed: 33 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -69,51 +69,47 @@ struct UberBxDF{S<:Spectrum}
6969
transport::UInt8
7070
type::UInt8
7171
bxdf_type::UInt8
72+
active::Bool
7273
end
7374

74-
function UberBxDF{S}(bxdf_type::UInt8;
75+
function Base.:&(b::UberBxDF, type::UInt8)::Bool
76+
return b.active && ((b.type & type) == b.type)
77+
end
78+
79+
UberBxDF{S}() where {S} = UberBxDF{S}(false, UInt8(0))
80+
81+
function UberBxDF{S}(active::Bool, bxdf_type::UInt8;
7582
r=Trace.RGBSpectrum(1f0), t=Trace.RGBSpectrum(1f0),
7683
a=0f0, b=0f0, η_a=0f0, η_b=0f0,
7784
distribution=TrowbridgeReitzDistribution(),
78-
fresnel_con=nothing,
79-
fresnel_di=nothing,
80-
fresnel_no=nothing,
85+
fresnel=nothing,
8186
type=UInt8(0),
8287
transport=UInt8(0)
8388
) where {S<:Spectrum}
8489
used_fresnel = UInt8(0)
85-
_fresnel_con = if isnothing(fresnel_con)
86-
FresnelConductor()
87-
else
88-
used_fresnel = UInt8(1)
89-
fresnel_con
90-
end
91-
_fresnel_di = if isnothing(fresnel_di)
92-
FresnelDielectric()
93-
else
94-
used_fresnel = UInt8(2)
95-
fresnel_di
96-
end
97-
_fresnel_no = if isnothing(fresnel_no)
98-
FresnelNoOp()
99-
else
100-
used_fresnel = UInt8(3)
101-
fresnel_no
90+
fresnel_con = FresnelConductor()
91+
fresnel_di = FresnelDielectric()
92+
fresnel_no = FresnelNoOp()
93+
94+
if !isnothing(fresnel)
95+
if fresnel isa FresnelConductor
96+
fresnel_con = fresnel
97+
used_fresnel = UInt8(1)
98+
elseif fresnel isa FresnelDielectric
99+
fresnel_di = fresnel
100+
used_fresnel = UInt8(2)
101+
elseif fresnel isa FresnelNoOp
102+
fresnel_no = fresnel
103+
used_fresnel = UInt8(3)
104+
end
102105
end
103-
return UberBxDF{S}(_fresnel_con, _fresnel_di, _fresnel_no, used_fresnel, r, t, a, b, η_a, η_b, distribution, transport, type, bxdf_type)
106+
_distribution = distribution isa TrowbridgeReitzDistribution ? distribution : TrowbridgeReitzDistribution()
107+
return UberBxDF{S}(fresnel_con, fresnel_di, fresnel_no, used_fresnel, r, t, a, b, η_a, η_b, _distribution, transport, type, bxdf_type, active)
104108
end
105109

106110
fresnel(f::UberBxDF)= getfield(f, Int(f.which_fresnel))
107111

108-
# @inline function sample_f(
109-
# b::UberBxDF, wo::Vec3f, sample::Point2f,
110-
# )::Tuple{Vec3f,Float32,RGBSpectrum,UInt8}
111-
# wi::Vec3f = cosine_sample_hemisphere(sample)
112-
# # Flipping the direction if necessary.
113-
# wo[3] < 0 && (wi = Vec3f(wi[1], wi[2], -wi[3]))
114-
# pdf::Float32 = compute_pdf(b, wo, wi)
115-
# wi, pdf, b(wo, wi), UInt8(0)
116-
# end
112+
117113
@inline function sample_f(s::UberBxDF, wo::Vec3f, sample::Point2f)::Tuple{Vec3f,Float32,RGBSpectrum,UInt8}
118114
if s.bxdf_type === SPECULAR_REFLECTION
119115
return sample_specular_reflection(s, wo, sample)
@@ -135,16 +131,12 @@ fresnel(f::UberBxDF)= getfield(f, Int(f.which_fresnel))
135131
return wi, pdf, s(wo, wi), UInt8(0)
136132
end
137133

138-
# """
139-
# Compute PDF value for the given directions.
140-
# In comparison, `sample_f` computes PDF value for the incident directions *it*
141-
# chooses given the outgoing direction, while this returns a value of PDF
142-
# for the given pair of directions.
143-
# """
144-
# @inline function compute_pdf(::UberBxDF, wo::Vec3f, wi::Vec3f)::Float32
145-
# same_hemisphere(wo, wi) ? abs(cos_θ(wi)) * (1.0f0 / π) : 0.0f0
146-
# end
147-
134+
"""
135+
Compute PDF value for the given directions.
136+
In comparison, `sample_f` computes PDF value for the incident directions *it*
137+
chooses given the outgoing direction, while this returns a value of PDF
138+
for the given pair of directions.
139+
"""
148140
@inline function compute_pdf(s::UberBxDF, wo::Vec3f, wi::Vec3f)::Float32
149141
if s.bxdf_type === FRESNEL_SPECULAR
150142
pdf_fresnel_specular(s, wo, wi)

src/mempool.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,6 @@ function Base.getindex(mref::MutableRef{T}) where {T}
138138
return unsafe_load(Ptr{T}(getfield(mref, :ptr)))
139139
end
140140

141-
function Base.show(io::IO, mref::MutableRef)
142-
show(io, mref[])
143-
end
144-
145141
function LifeCycle(f::Function, pool)
146142
try
147143
f(pool)

src/primitive.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ struct GeometricPrimitive{T<:AbstractShape,M<:UberMaterial} <: Primitive
99
end
1010
end
1111

12-
function intersect!(
12+
function intersect_p!(
1313
pool, p::GeometricPrimitive{T}, ray::Union{Ray,RayDifferentials},
14-
) where T<:AbstractShape
14+
)::Tuple{Bool, SurfaceInteraction} where T<:AbstractShape
1515

1616
shape = p.shape
1717
intersects, t_hit, interaction = intersect(pool, shape, ray)
@@ -20,7 +20,7 @@ function intersect!(
2020
return true, interaction
2121
end
2222

23-
@inline function intersect_p(
23+
@noinline function intersect_p(
2424
pool, p::GeometricPrimitive, ray::Union{Ray,RayDifferentials},
2525
)
2626
intersect_p(pool, p.shape, ray)

src/reflection/bxdf.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ const BSDF_GLOSSY = UInt8(0b01000)
66
const BSDF_SPECULAR = UInt8(0b10000)
77
const BSDF_ALL = UInt8(0b11111)
88

9-
function Base.:&(b::UberBxDF, type::UInt8)::Bool
10-
(b.type & type) == b.type
11-
end
129

1310
@inline function same_hemisphere(w::Vec3f, wp::Union{Vec3f,Normal3f})::Bool
1411
w[3] * wp[3] > 0

0 commit comments

Comments
 (0)