1 #!/usr/bin/perl |
1 #!/usr/bin/perl |
2 |
2 |
3 # Make a nice multi-view picture of a luminaire |
3 # Make a four-view picture of the photometry of a luminaire |
4 # |
4 # |
5 # This is based on objpict.pl that renders four-view |
5 # This is inspired by objpict.pl that renders four-view |
6 # images of objects that are not light sources. |
6 # images of objects that are not light sources. |
7 # |
7 # |
8 # Written by Axel Jacobs |
8 # Written by Axel Jacobs <axel@jaloxa.eu> |
9 |
9 |
10 use strict; |
10 use strict; |
11 use warnings; |
11 use warnings; |
12 |
12 |
13 use File::Temp qw/ tempdir /; |
13 use File::Temp qw/ tempdir /; |
14 #my $td = tempdir( CLEANUP => 1 ); |
14 my $td = tempdir( CLEANUP => 1 ); |
15 my $td = "tmp"; |
15 use File::Copy qw(copy); |
16 |
16 |
17 #my $xres = 1024; |
17 my $res = 1024; # Default output image dimensions |
18 #my $yres = 1024; |
|
19 my $xres = 600; |
|
20 my $yres = 600; |
|
21 my $tiny = 0.01; |
18 my $tiny = 0.01; |
|
19 my $maxsize = 0.001; # max luminaire size after scaling |
22 my $is_ies = 0; |
20 my $is_ies = 0; |
23 my $rpict_cmd = "rpict -ab 0 -ds 0 -dv -av 0 0 0 -x $xres -y $yres"; |
|
24 my $pcond_cmd = "pcond -l"; |
|
25 |
21 |
26 my $ies = "$td/dist.ies"; |
22 my $ies = "$td/dist.ies"; |
27 my $fittings = "$td/fitting.rad"; |
23 my $lumi = "$td/lumi.rad"; # Fitting as given on cmd line, or as generated by ies2rad |
28 my $material = "$td/lt.mat"; |
24 my $lumi2 = "$td/lumi2.rad"; # Fitting scaled to size |
29 my $testroom1 = "$td/testroom1.rad"; |
25 my $mat = "$td/lt.mat"; |
30 my $testroom2 = "$td/testroom2.rad"; |
26 my $room1 = "$td/room1.rad"; |
31 my $testroom3 = "$td/testroom3.rad"; |
27 my $room2 = "$td/room2.rad"; |
32 my $testroom4 = "$td/testroom4.rad"; |
28 my $room3 = "$td/room3.rad"; |
33 my $octree1 = "$td/lt1.oct"; |
29 my $room4 = "$td/room4.rad"; |
34 my $octree2 = "$td/lt2.oct"; |
30 my $oct1 = "$td/lt1.oct"; |
35 my $octree3 = "$td/lt3.oct"; |
31 my $oct2 = "$td/lt2.oct"; |
36 my $octree4 = "$td/lt4.oct"; |
32 my $oct3 = "$td/lt3.oct"; |
|
33 my $oct4 = "$td/lt4.oct"; |
37 |
34 |
38 # Parse command line arguments |
35 # Parse command line arguments |
39 if ("$ARGV[0]" eq '-i') { # File is an IES file, not Radiance luminaire |
36 while ($#ARGV >= 0) { |
40 $is_ies = 1; |
37 $_ = $ARGV[0]; |
41 shift @ARGV; |
38 if (m/-i/) { # File is an IES file, not Radiance luminaire |
42 } |
39 $is_ies = 1; |
43 # We need at least one Radiance file or a scene on STDIN (but not both) |
40 } elsif (m/-d/) { # Resolution of the output HDR image |
44 if ($#ARGV < 0) { |
41 $res = $ARGV[1]; |
45 open(FH, ">$td/stdin.rad") or |
42 shift @ARGV; |
46 die("objview: Can't write to temporary file $td/stdin.rad\n"); |
43 |
47 while (<>) { |
44 } elsif (m/^-/) { # Oops! Illegal option |
48 print FH; |
45 die("ltpict: bad option \"$ARGV[0]\"\n"); |
|
46 } else { |
|
47 last; # No more options. What's left is the actual file name. |
49 } |
48 } |
50 # Pretend stdin.rad was passed as argument. |
49 shift @ARGV; |
51 @ARGV = ("$td/stdin.rad"); |
|
52 } |
50 } |
53 |
51 |
|
52 # We need one Radiance luminaire or an IES file |
|
53 if ($is_ies == 0) { |
|
54 # Input file is a Radiance luminaire |
|
55 copy $ARGV[0], $lumi or |
|
56 die("ltpict: Cannot copy file '$ARGV[0]' to $lumi\n"); |
|
57 } else { |
|
58 # Input file is IES photometry |
|
59 system "ies2rad -p $td -o lumi $ARGV[0]"; |
|
60 } |
54 |
61 |
55 # Scale fitting and center at origin |
62 my $res2 = $res / 2; # Each rendering is half the size of final composite |
56 my $dimstr = `getbbox -h @ARGV`; |
63 |
|
64 # Scale luminaire and center at origin |
|
65 my $dimstr = `getbbox -h $lumi`; |
57 chomp $dimstr; |
66 chomp $dimstr; |
58 # Values returned by getbbox are indented and delimited with multiple spaces. |
67 # Values returned by getbbox are indented and delimited with multiple spaces. |
59 $dimstr =~ s/^\s+//; # remove leading spaces |
68 $dimstr =~ s/^\s+//; # remove leading spaces |
60 my @dims = split(/\s+/, $dimstr); # convert to array |
69 my @dims = split(/\s+/, $dimstr); # convert to array |
61 |
70 |
62 # Find largest axes-aligned dimension |
71 # Find largest axes-aligned dimension |
63 my @diffs = ($dims[1]-$dims[0], $dims[3]-$dims[2], $dims[5]-$dims[4]); |
72 my @diffs = ($dims[1]-$dims[0], $dims[3]-$dims[2], $dims[5]-$dims[4]); |
64 @diffs = reverse sort { $a <=> $b } @diffs; |
73 @diffs = reverse sort { $a <=> $b } @diffs; |
65 my $size = $diffs[0]; |
74 my $size = $diffs[0]; |
66 |
75 |
67 # Move fitting so centre is at origin |
76 # Move luminaire so centre is at origin, and scale |
68 my $xtrans = -1.0 * ($dims[0] + $dims[1]) / 2; |
77 my $xtrans = -1.0 * ($dims[0] + $dims[1]) / 2; |
69 my $ytrans = -1.0 * ($dims[2] + $dims[3]) / 2; |
78 my $ytrans = -1.0 * ($dims[2] + $dims[3]) / 2; |
70 my $ztrans = -1.0 * ($dims[4] + $dims[5]) / 2; |
79 my $ztrans = -1.0 * ($dims[4] + $dims[5]) / 2; |
71 # Scale so that largest object dimension is unity |
80 my $scale = $maxsize / $size; |
72 my $scale = 0.001 / $size; |
|
73 |
81 |
74 my $fitting = "$td/fitting.rad"; |
82 open(FH, ">$lumi2") or |
75 open(FH, ">$fitting") or |
83 die("ltpict: Cannot write to temporary file $lumi"); |
76 die("Can\'t write to temporary file $fitting"); |
84 print FH "!xform -t $xtrans $ytrans $ztrans -s $scale $lumi"; |
77 print FH "!xform -t $xtrans $ytrans $ztrans -s $scale @ARGV"; |
|
78 close FH; |
85 close FH; |
79 |
86 |
80 |
87 |
81 # Material for the room |
88 # Material for the room |
82 open(FH, ">$material") or |
89 open(FH, ">$mat") or |
83 die("Can\'t write to temporary file $material"); |
90 die("ltpict: Cannot write to temporary file $mat"); |
84 print FH "void plastic wall_mat 0 0 5 .5 .5 .5 0 0"; |
91 print FH "void plastic wall_mat 0 0 5 .5 .5 .5 0 0"; |
85 close FH; |
92 close FH; |
86 |
93 |
87 |
94 |
88 # Different 'room' geometry for different views |
95 # Different 'room' geometry for different views |
89 my $OFFSET = 0.1; |
96 my $offset = 0.1; |
90 open(FH, ">$testroom1") or die("Can't write to temporary file $testroom1"); |
97 |
91 # C0-C180 |
98 # C0-C180 |
92 print FH "wall_mat polygon box.4620 0 0 12 -$OFFSET -5 5 -$OFFSET 5 5 -$OFFSET 5 -5 -$OFFSET -5 -5"; |
99 open(FH, ">$room1") or die("ltpict: Cannot write to temporary file $room1"); |
|
100 print FH "wall_mat polygon box.4620 0 0 12 -$offset -5 5 -$offset 5 5 -$offset 5 -5 -$offset -5 -5"; |
93 close(FH); |
101 close(FH); |
94 |
102 |
95 open(FH, ">$testroom2") or die("Can't write to temporary file $testroom2"); |
|
96 # C90-C270 |
103 # C90-C270 |
97 print FH "wall_mat polygon box.1540 0 0 12 5 $OFFSET -5 5 $OFFSET 5 -5 $OFFSET 5 -5 $OFFSET -5"; |
104 open(FH, ">$room2") or die("ltpict: Cannot write to temporary file $room2"); |
|
105 print FH "wall_mat polygon box.1540 0 0 12 5 $offset -5 5 $offset 5 -5 $offset 5 -5 $offset -5"; |
98 close(FH); |
106 close(FH); |
99 |
107 |
100 open(FH, ">$testroom3") or die("Can't write to temporary file $testroom3"); |
|
101 # Lower hemisphere |
108 # Lower hemisphere |
|
109 open(FH, ">$room3") or die("ltpict: Cannot write to temporary file $room3"); |
102 print FH "wall_mat bubble lower 0 0 4 0 0 $dims[4] 5"; |
110 print FH "wall_mat bubble lower 0 0 4 0 0 $dims[4] 5"; |
103 close(FH); |
111 close(FH); |
104 |
112 |
105 open(FH, ">$testroom4") or die("Can't write to temporary file $testroom4"); |
|
106 # Upper hemisphere |
113 # Upper hemisphere |
|
114 open(FH, ">$room4") or die("ltpict: Cannot write to temporary file $room4"); |
107 print FH "wall_mat bubble upper 0 0 4 0 0 $dims[5] 5"; |
115 print FH "wall_mat bubble upper 0 0 4 0 0 $dims[5] 5"; |
108 close(FH); |
116 close(FH); |
109 |
117 |
110 |
118 |
111 # Get bbox again, for the translated and scaled fitting. |
119 # Get bbox again, for the translated and scaled luminaire. |
112 $dimstr = `getbbox -h $fitting`; |
120 $dimstr = `getbbox -h $lumi2`; |
113 chomp $dimstr; |
121 chomp $dimstr; |
114 # Values returned by getbbox are indented and delimited with multiple spaces. |
122 # Values returned by getbbox are indented and delimited with multiple spaces. |
115 $dimstr =~ s/^\s+//; # remove leading spaces |
123 $dimstr =~ s/^\s+//; # remove leading spaces |
116 @dims = split(/\s+/, $dimstr); # convert to array |
124 @dims = split(/\s+/, $dimstr); # convert to array |
117 |
125 |
121 my $zcent3 = $dims[4] - $tiny; |
129 my $zcent3 = $dims[4] - $tiny; |
122 my $vw3 = "-vta -vp 0 0 $zcent3 -vd 0 0 -1 -vu 0 1 0 -vh 180 -vv 180"; |
130 my $vw3 = "-vta -vp 0 0 $zcent3 -vd 0 0 -1 -vu 0 1 0 -vh 180 -vv 180"; |
123 my $zcent4 = $dims[5] + $tiny; |
131 my $zcent4 = $dims[5] + $tiny; |
124 my $vw4 = "-vta -vp 0 0 $zcent4 -vd 0 0 1 -vu 0 1 0 -vh 180 -vv 180"; |
132 my $vw4 = "-vta -vp 0 0 $zcent4 -vd 0 0 1 -vu 0 1 0 -vh 180 -vv 180"; |
125 |
133 |
126 system "oconv $material $testroom1 $fitting > $octree1"; |
134 system "oconv $mat $room1 $lumi2 > $oct1"; |
127 system "oconv $material $testroom2 $fitting > $octree2"; |
135 system "oconv $mat $room2 $lumi2 > $oct2"; |
128 system "oconv $material $testroom3 $fitting > $octree3"; |
136 system "oconv $mat $room3 $lumi2 > $oct3"; |
129 system "oconv $material $testroom4 $fitting > $octree4"; |
137 system "oconv $mat $room4 $lumi2 > $oct4"; |
130 |
138 |
131 # Render four different views of the objects |
139 # Render four different views of the objects |
132 system "$rpict_cmd $vw1 $octree1 > $td/right.hdr"; |
140 my $rpict_cmd = "rpict -ab 0 -ds 0 -dv -av 0 0 0 -x $res2 -y $res2"; |
133 system "$rpict_cmd $vw2 $octree2 > $td/front.hdr"; |
141 system "$rpict_cmd $vw1 $oct1 > $td/right.hdr"; |
134 system "$rpict_cmd $vw3 $octree3 > $td/down.hdr"; |
142 system "$rpict_cmd $vw2 $oct2 > $td/front.hdr"; |
135 system "$rpict_cmd $vw4 $octree4 > $td/up.hdr"; |
143 system "$rpict_cmd $vw3 $oct3 > $td/down.hdr"; |
|
144 system "$rpict_cmd $vw4 $oct4 > $td/up.hdr"; |
136 |
145 |
137 # Compose the four views into one image |
146 # Compose the four views into one image |
138 my $cmd; |
147 my $vtl = "$td/vtl.hdr"; # The two parallel views |
139 my $vtl = "$td/vtl.hdr"; |
148 my $vta = "$td/vta.hdr"; # The two fisheye views |
140 my $vta = "$td/vta.hdr"; |
|
141 |
149 |
142 # Auto-expose right/front and down/up pairs separately |
150 # Auto-expose right/front and down/up pairs separately |
143 system "pcompos $td/right.hdr 0 0 $td/front.hdr $xres 0 > $td/rf.hdr"; |
151 my $pcond_cmd = "pcond -l"; |
|
152 system "pcompos -a 2 $td/right.hdr $td/front.hdr > $td/rf.hdr"; |
144 system "$pcond_cmd $td/rf.hdr > $vtl"; |
153 system "$pcond_cmd $td/rf.hdr > $vtl"; |
145 system "pcompos $td/down.hdr 0 0 $td/up.hdr $xres 0 > $td/du.hdr"; |
154 system "pcompos -a 2 $td/down.hdr $td/up.hdr > $td/du.hdr"; |
146 system "$pcond_cmd $td/du.hdr > $vta"; |
155 system "$pcond_cmd $td/du.hdr > $vta"; |
147 |
156 |
148 # Combine top two images with bottom row |
157 # Combine top two images with bottom row. Output HDR. |
149 exec "pcompos -a 1 $vtl $vta"; |
158 exec "pcompos -a 1 $vtl $vta"; |
150 |
159 |
151 #EOF |
160 #EOF |