1
1
use core:: f64;
2
+ use std:: sync:: { Arc , RwLock , Barrier } ;
3
+ use std:: { thread, u32} ;
2
4
use std:: { env, usize} ;
3
5
mod sceneparser;
4
6
mod camera;
@@ -14,44 +16,76 @@ use image::ImageError;
14
16
use materials:: MaterialType ;
15
17
use object3d:: Group ;
16
18
use object3d:: Object3d ;
19
+ // use threadpool::ThreadPool;
17
20
use vecmat:: vector:: Vector2 ;
18
- use vecmat :: vector :: Vector3 ;
19
- use image:: { Rgb , ImageResult , ImageBuffer } ;
20
-
21
+ use image :: { Rgb , ImageResult } ;
22
+ use image:: RgbImage ;
23
+ // use image::ImageBuffer;
21
24
use crate :: { photon:: { HitPoint , KDTree , Photon } , sceneparser:: build_sceneparser} ;
22
25
use crate :: ray:: Ray ;
23
26
use crate :: matrix:: trunc;
24
- use rand:: { thread_rng, Rng } ;
25
27
26
28
static PHOTON_NUMBER : u32 = 100000 ;
27
29
static ROUND_NUMBER : u32 = 3 ;
28
30
static SAMPLE_NUMBER : u32 = 3 ;
29
- static _PARALLEL_NUMBER : u32 = 8 ;
30
- static _PHOTONS_PER_ROUND: u32 = PHOTON_NUMBER / _PARALLEL_NUMBER ;
31
+ static PARALLEL_NUMBER : usize = 8 ;
32
+ static _PHOTONS_PER_ROUND: u32 = PHOTON_NUMBER / PARALLEL_NUMBER as u32 ;
31
33
static TMIN : f64 = 0.015 ;
32
34
33
- fn render ( pic : & Vec < Vec < HitPoint > > , output_file : & str ) -> ImageResult < ( ) > {
34
- let width = pic. len ( ) as u32 ;
35
- let height = pic[ 0 ] . len ( ) as u32 ;
36
- let img = ImageBuffer :: from_fn (
37
- width,
38
- height,
39
- |x, y| {
40
- let point = & pic[ x as usize ] [ ( height - 1 - y) as usize ] ;
41
- let area = f64:: consts:: PI * point. radius * point. radius ;
42
- let number = ( PHOTON_NUMBER * ROUND_NUMBER ) as f64 ;
43
- Rgb ( [
44
- trunc ( point. tau . x ( ) / ( area * number) ) ,
45
- trunc ( point. tau . y ( ) / ( area * number) ) ,
46
- trunc ( point. tau . z ( ) / ( area * number) ) ,
47
- ] )
35
+ fn render ( pic : & Vec < Arc < RwLock < Vec < Vec < HitPoint > > > > > , output_file : & str , width : u32 , height : u32 ) -> ImageResult < ( ) > {
36
+ let number = ( PHOTON_NUMBER * ROUND_NUMBER ) as f64 ;
37
+ let mut img = RgbImage :: new ( width, height) ;
38
+ // for x in 0 .. width {
39
+ // let interval = width as usize / PARALLEL_NUMBER;
40
+ // let dim_1 = x as usize / interval;
41
+ // let dim_2 = x as usize % interval;
42
+ // // let point_vector = &pic[dim_1].read().unwrap();
43
+ // for y in 0 .. height {
44
+ // let point = &pic[dim_1].read().unwrap()[dim_2][(height - 1 - y) as usize];
45
+ // // let point = &point_vector[dim_2][(height - 1 - y) as usize];
46
+ // let area = f64::consts::PI * point.radius * point.radius;
47
+ // *img.get_pixel_mut(x, y) = Rgb([
48
+ // trunc(point.tau.x() / (area * number)),
49
+ // trunc(point.tau.y() / (area * number)),
50
+ // trunc(point.tau.z() / (area * number)),
51
+ // ]);
52
+ // }
53
+ // }
54
+ for dim_1 in 0 .. PARALLEL_NUMBER {
55
+ for dim_2 in 0 .. width as usize / PARALLEL_NUMBER {
56
+ for y in 0 .. height {
57
+ let x = dim_1 * width as usize / PARALLEL_NUMBER + dim_2;
58
+ let point = & pic[ dim_1] . read ( ) . unwrap ( ) [ dim_2] [ ( height - 1 - y) as usize ] ;
59
+ let area = f64:: consts:: PI * point. radius * point. radius ;
60
+ * img. get_pixel_mut ( x as u32 , y) = Rgb ( [
61
+ trunc ( point. tau . x ( ) / ( area * number) ) ,
62
+ trunc ( point. tau . y ( ) / ( area * number) ) ,
63
+ trunc ( point. tau . z ( ) / ( area * number) ) ,
64
+ ] ) ;
65
+ }
48
66
}
49
- ) ;
67
+ }
68
+ // let img = ImageBuffer::from_fn(
69
+ // width,
70
+ // height,
71
+ // |x, y| {
72
+ // let interval = width as usize / PARALLEL_NUMBER;
73
+ // let dim_1 = x as usize / interval;
74
+ // let dim_2 = x as usize % interval;
75
+ // let point = &pic[dim_1].read().unwrap()[dim_2][(height - 1 - y) as usize];
76
+ // let area = f64::consts::PI * point.radius * point.radius;
77
+ // Rgb([
78
+ // trunc(point.tau.x() / (area * number)),
79
+ // trunc(point.tau.y() / (area * number)),
80
+ // trunc(point.tau.z() / (area * number)),
81
+ // ])
82
+ // }
83
+ // );
50
84
img. save ( output_file) ?;
51
85
Ok ( ( ) )
52
86
}
53
87
54
- fn photon_trace ( group : & Box < Group > , mut ray : Ray , photon_map : & mut Vec < Photon > ) {
88
+ fn photon_trace ( group : & Arc < Group > , mut ray : Ray , photon_map : & mut Vec < Photon > ) {
55
89
let mut depth = 0 ;
56
90
loop {
57
91
if depth > 100 {
@@ -84,8 +118,7 @@ fn photon_trace(group: &Box<Group>, mut ray: Ray, photon_map: &mut Vec<Photon>)
84
118
}
85
119
86
120
fn ray_trace (
87
- x : usize , y : usize , group : & Box < Group > , mut ray : Ray , kd_tree : & KDTree ,
88
- picture : & Vec < Vec < HitPoint > > , buffer : & mut Vec < Vec < HitPoint > >
121
+ group : & Arc < Group > , mut ray : Ray , kd_tree : & Arc < KDTree > , radius : f64 , buffer_pixel : & mut HitPoint
89
122
) {
90
123
let mut depth = 0 ;
91
124
loop {
@@ -100,9 +133,9 @@ fn ray_trace(
100
133
depth += 1 ;
101
134
match material. get_type ( ) {
102
135
& MaterialType :: DIFFUSE => {
103
- buffer [ x ] [ y ] . radius = picture [ x ] [ y ] . radius ;
104
- buffer [ x ] [ y ] . pos = Some ( position) ;
105
- kd_tree. search ( & mut buffer [ x ] [ y ] , color, hit. get_normal ( ) , ray. get_flux ( ) ) ;
136
+ buffer_pixel . radius = radius;
137
+ buffer_pixel . pos = Some ( position) ;
138
+ kd_tree. search ( buffer_pixel , color, hit. get_normal ( ) , ray. get_flux ( ) ) ;
106
139
break ;
107
140
} ,
108
141
& MaterialType :: SPECULAR | & MaterialType :: REFRACTION => {
@@ -127,10 +160,10 @@ fn main() -> Result<(), ImageError> {
127
160
let group = parser. group ;
128
161
let width = camera. get_width ( ) as usize ;
129
162
let height = camera. get_height ( ) as usize ;
130
- let mut picture = vec ! [ vec![ HitPoint :: new( ) ; height] ; width] ;
131
- let mut buffer = vec ! [ vec![ HitPoint :: new( ) ; height] ; width] ;
163
+ let pictures: Vec < Arc < RwLock < Vec < Vec < HitPoint > > > > > =
164
+ vec ! [ Arc :: new( RwLock :: new( vec![ vec![ HitPoint :: new( ) ; height] ; width / PARALLEL_NUMBER ] ) ) ; PARALLEL_NUMBER ] ;
165
+ let barrier = Arc :: new ( Barrier :: new ( PARALLEL_NUMBER + 1 ) ) ;
132
166
133
- let mut rng = thread_rng ( ) ;
134
167
for round in 0 .. ROUND_NUMBER {
135
168
let mut photon_map: Vec < Photon > = Vec :: new ( ) ;
136
169
for light in & lights {
@@ -141,34 +174,54 @@ fn main() -> Result<(), ImageError> {
141
174
}
142
175
println ! ( "Round {} photon pass complete" , & round) ;
143
176
let kd_tree = KDTree :: new ( photon_map) ;
177
+ let arc_kd_tree = Arc :: new ( kd_tree) ;
144
178
println ! ( "Round {} kdtree build complete" , & round) ;
145
- for x in 0 .. width {
146
- for y in 0 .. height {
147
- buffer[ x] [ y] . tau = Vector3 :: < f64 > :: from ( [ 0. , 0. , 0. ] ) ;
148
- buffer[ x] [ y] . n = 0. ;
149
- for _ in 0 .. SAMPLE_NUMBER {
150
- let mut ray = camera. generate_ray ( & Vector2 :: < f64 > :: from ( [
151
- x as f64 + rng. gen_range ( 0. .. 1. ) ,
152
- y as f64 + rng. gen_range ( 0. .. 1. )
153
- ] ) ) ;
154
- ray. set_color ( * ray. get_flux ( ) / ( SAMPLE_NUMBER as f64 ) ) ;
155
- ray_trace ( x, y, & group, ray, & kd_tree, & picture, & mut buffer) ;
156
- }
157
- if round == 0 {
158
- picture[ x] [ y] . n = buffer[ x] [ y] . n ;
159
- picture[ x] [ y] . tau = buffer[ x] [ y] . tau ;
160
- } else {
161
- if picture[ x] [ y] . n + buffer[ x] [ y] . n > 0. {
162
- let ratio = ( picture[ x] [ y] . n + photon:: ALPHA * buffer[ x] [ y] . n ) / ( picture[ x] [ y] . n + buffer[ x] [ y] . n ) ;
163
- picture[ x] [ y] . radius *= f64:: sqrt ( ratio) ;
164
- picture[ x] [ y] . tau = ( picture[ x] [ y] . tau + buffer[ x] [ y] . tau ) * ratio;
165
- picture[ x] [ y] . n += buffer[ x] [ y] . n * ratio;
179
+ for i in 0 .. PARALLEL_NUMBER as usize {
180
+ let group = group. clone ( ) ;
181
+ let camera = camera. clone ( ) ;
182
+ let arc_kd_tree = arc_kd_tree. clone ( ) ;
183
+ let picture = pictures[ i] . clone ( ) ;
184
+ let barrier = barrier. clone ( ) ;
185
+ thread:: spawn ( move || {
186
+ let column_begin = width * i / PARALLEL_NUMBER ;
187
+ let column_end = width * ( i + 1 ) / PARALLEL_NUMBER ;
188
+ println ! ( "thread {} spawns with column range [{}, {})" , & i, & column_begin, & column_end) ;
189
+ let mut buffer = vec ! [ vec![ HitPoint :: new( ) ; height] ; column_end - column_begin] ;
190
+ let mut picture = picture. write ( ) . unwrap ( ) ;
191
+ for ( x, global_x) in ( column_begin .. column_end) . enumerate ( ) {
192
+ for y in 0 .. height {
193
+ let buffer_pixel = & mut buffer[ x] [ y] ;
194
+ let picture_pixel = & mut picture[ x] [ y] ;
195
+ for _ in 0 .. SAMPLE_NUMBER {
196
+ let dest_x = global_x as f64 + rand:: random :: < f64 > ( ) ;
197
+ let dest_y = y as f64 + rand:: random :: < f64 > ( ) ;
198
+ let mut ray = camera. generate_ray ( & Vector2 :: < f64 > :: from ( [
199
+ dest_x,
200
+ dest_y
201
+ ] ) ) ;
202
+ ray. set_color ( * ray. get_flux ( ) / ( SAMPLE_NUMBER as f64 ) ) ;
203
+ ray_trace ( & group, ray, & arc_kd_tree, picture_pixel. radius , buffer_pixel) ;
204
+ }
205
+ if round == 0 {
206
+ picture_pixel. n = buffer_pixel. n ;
207
+ picture_pixel. tau = buffer_pixel. tau ;
208
+ } else {
209
+ if picture_pixel. n + buffer_pixel. n > 0. {
210
+ let ratio = ( picture_pixel. n + photon:: ALPHA * buffer_pixel. n ) / ( picture_pixel. n + buffer_pixel. n ) ;
211
+ picture_pixel. radius = picture_pixel. radius * f64:: sqrt ( ratio) ;
212
+ picture_pixel. tau = ( picture_pixel. tau + buffer_pixel. tau ) * ratio;
213
+ picture_pixel. n = picture_pixel. n + buffer_pixel. n * ratio;
214
+ }
215
+ }
166
216
}
167
217
}
168
- }
218
+ drop ( picture) ;
219
+ barrier. wait ( ) ;
220
+ } ) ;
169
221
}
222
+ barrier. wait ( ) ;
170
223
println ! ( "Round {} complete" , & round) ;
171
224
}
172
- render ( & picture , & output_file) ?;
225
+ render ( & pictures , & output_file, width as u32 , height as u32 ) ?;
173
226
Ok ( ( ) )
174
227
}
0 commit comments