00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "pbrt.h"
00026 #include "film.h"
00027 #include "color.h"
00028 #include "paramset.h"
00029 #include "tonemap.h"
00030 #include "sampling.h"
00031
00032 class ImageFilm : public Film {
00033 public:
00034
00035 ImageFilm(int xres, int yres,
00036 Filter *filt, const float crop[4],
00037 const string &filename, bool premult,
00038 int wf);
00039 ~ImageFilm() {
00040 delete pixels;
00041 delete filter;
00042 delete[] filterTable;
00043 }
00044 void AddSample(const Sample &sample, const Ray &ray,
00045 const Spectrum &L, float alpha);
00046 void GetSampleExtent(int *xstart, int *xend,
00047 int *ystart, int *yend) const;
00048 void WriteImage();
00049 private:
00050
00051 Filter *filter;
00052 int writeFrequency, sampleCount;
00053 string filename;
00054 bool premultiplyAlpha;
00055 float cropWindow[4];
00056 int xPixelStart, yPixelStart, xPixelCount, yPixelCount;
00057 struct Pixel {
00058 Pixel() : L(0.f) {
00059 alpha = 0.f;
00060 weightSum = 0.f;
00061 }
00062 Spectrum L;
00063 float alpha, weightSum;
00064 };
00065 BlockedArray<Pixel> *pixels;
00066 float *filterTable;
00067 };
00068
00069 ImageFilm::ImageFilm(int xres, int yres,
00070 Filter *filt, const float crop[4],
00071 const string &fn, bool premult, int wf)
00072 : Film(xres, yres) {
00073 filter = filt;
00074 memcpy(cropWindow, crop, 4 * sizeof(float));
00075 filename = fn;
00076 premultiplyAlpha = premult;
00077 writeFrequency = sampleCount = wf;
00078
00079 xPixelStart = Ceil2Int(xResolution * cropWindow[0]);
00080 xPixelCount =
00081 max(1, Ceil2Int(xResolution * cropWindow[1]) - xPixelStart);
00082 yPixelStart =
00083 Ceil2Int(yResolution * cropWindow[2]);
00084 yPixelCount =
00085 max(1, Ceil2Int(yResolution * cropWindow[3]) - yPixelStart);
00086
00087 pixels = new BlockedArray<Pixel>(xPixelCount, yPixelCount);
00088
00089 #define FILTER_TABLE_SIZE 16
00090 filterTable =
00091 new float[FILTER_TABLE_SIZE * FILTER_TABLE_SIZE];
00092 float *ftp = filterTable;
00093 for (int y = 0; y < FILTER_TABLE_SIZE; ++y) {
00094 float fy = ((float)y + .5f) * filter->yWidth /
00095 FILTER_TABLE_SIZE;
00096 for (int x = 0; x < FILTER_TABLE_SIZE; ++x) {
00097 float fx = ((float)x + .5f) * filter->xWidth /
00098 FILTER_TABLE_SIZE;
00099 *ftp++ = filter->Evaluate(fx, fy);
00100 }
00101 }
00102 }
00103 void ImageFilm::AddSample(const Sample &sample,
00104 const Ray &ray, const Spectrum &L, float alpha) {
00105
00106 float dImageX = sample.imageX - 0.5f;
00107 float dImageY = sample.imageY - 0.5f;
00108 int x0 = Ceil2Int (dImageX - filter->xWidth);
00109 int x1 = Floor2Int(dImageX + filter->xWidth);
00110 int y0 = Ceil2Int (dImageY - filter->yWidth);
00111 int y1 = Floor2Int(dImageY + filter->yWidth);
00112 x0 = max(x0, xPixelStart);
00113 x1 = min(x1, xPixelStart + xPixelCount - 1);
00114 y0 = max(y0, yPixelStart);
00115 y1 = min(y1, yPixelStart + yPixelCount - 1);
00116 if ((x1-x0) < 0 || (y1-y0) < 0) return;
00117
00118
00119 int *ifx = (int *)alloca((x1-x0+1) * sizeof(int));
00120 for (int x = x0; x <= x1; ++x) {
00121 float fx = fabsf((x - dImageX) *
00122 filter->invXWidth * FILTER_TABLE_SIZE);
00123 ifx[x-x0] = min(Floor2Int(fx), FILTER_TABLE_SIZE-1);
00124 }
00125 int *ify = (int *)alloca((y1-y0+1) * sizeof(int));
00126 for (int y = y0; y <= y1; ++y) {
00127 float fy = fabsf((y - dImageY) *
00128 filter->invYWidth * FILTER_TABLE_SIZE);
00129 ify[y-y0] = min(Floor2Int(fy), FILTER_TABLE_SIZE-1);
00130 }
00131 for (int y = y0; y <= y1; ++y)
00132 for (int x = x0; x <= x1; ++x) {
00133
00134 int offset = ify[y-y0]*FILTER_TABLE_SIZE + ifx[x-x0];
00135 float filterWt = filterTable[offset];
00136
00137 Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
00138 pixel.L.AddWeighted(filterWt, L);
00139 pixel.alpha += alpha * filterWt;
00140 pixel.weightSum += filterWt;
00141 }
00142
00143 if (--sampleCount == 0) {
00144 WriteImage();
00145 sampleCount = writeFrequency;
00146 }
00147 }
00148 void ImageFilm::GetSampleExtent(int *xstart,
00149 int *xend, int *ystart, int *yend) const {
00150 *xstart = Floor2Int(xPixelStart + .5f - filter->xWidth);
00151 *xend = Floor2Int(xPixelStart + .5f + xPixelCount +
00152 filter->xWidth);
00153 *ystart = Floor2Int(yPixelStart + .5f - filter->yWidth);
00154 *yend = Floor2Int(yPixelStart + .5f + yPixelCount +
00155 filter->yWidth);
00156 }
00157 void ImageFilm::WriteImage() {
00158
00159 int nPix = xPixelCount * yPixelCount;
00160 float *rgb = new float[3*nPix], *alpha = new float[nPix];
00161 int offset = 0;
00162 for (int y = 0; y < yPixelCount; ++y) {
00163 for (int x = 0; x < xPixelCount; ++x) {
00164
00165 float xyz[3];
00166 (*pixels)(x, y).L.XYZ(xyz);
00167 const float
00168 rWeight[3] = { 3.240479f, -1.537150f, -0.498535f };
00169 const float
00170 gWeight[3] = {-0.969256f, 1.875991f, 0.041556f };
00171 const float
00172 bWeight[3] = { 0.055648f, -0.204043f, 1.057311f };
00173 rgb[3*offset ] = rWeight[0]*xyz[0] +
00174 rWeight[1]*xyz[1] +
00175 rWeight[2]*xyz[2];
00176 rgb[3*offset+1] = gWeight[0]*xyz[0] +
00177 gWeight[1]*xyz[1] +
00178 gWeight[2]*xyz[2];
00179 rgb[3*offset+2] = bWeight[0]*xyz[0] +
00180 bWeight[1]*xyz[1] +
00181 bWeight[2]*xyz[2];
00182 alpha[offset] = (*pixels)(x, y).alpha;
00183
00184 float weightSum = (*pixels)(x, y).weightSum;
00185 if (weightSum != 0.f) {
00186 float invWt = 1.f / weightSum;
00187 rgb[3*offset ] =
00188 Clamp(rgb[3*offset ] * invWt, 0.f, INFINITY);
00189 rgb[3*offset+1] =
00190 Clamp(rgb[3*offset+1] * invWt, 0.f, INFINITY);
00191 rgb[3*offset+2] =
00192 Clamp(rgb[3*offset+2] * invWt, 0.f, INFINITY);
00193 alpha[offset] = Clamp(alpha[offset] * invWt, 0.f, 1.f);
00194 }
00195
00196 if (premultiplyAlpha) {
00197 rgb[3*offset ] *= alpha[offset];
00198 rgb[3*offset+1] *= alpha[offset];
00199 rgb[3*offset+2] *= alpha[offset];
00200 }
00201 ++offset;
00202 }
00203 }
00204
00205 WriteRGBAImage(filename, rgb, alpha,
00206 xPixelCount, yPixelCount,
00207 xResolution, yResolution,
00208 xPixelStart, yPixelStart);
00209
00210 delete[] alpha;
00211 delete[] rgb;
00212 }
00213 extern "C" DLLEXPORT Film *CreateFilm(const ParamSet ¶ms, Filter *filter)
00214 {
00215 string filename = params.FindOneString("filename", "pbrt.exr");
00216 bool premultiplyAlpha = params.FindOneBool("premultiplyalpha", true);
00217
00218 int xres = params.FindOneInt("xresolution", 640);
00219 int yres = params.FindOneInt("yresolution", 480);
00220 float crop[4] = { 0, 1, 0, 1 };
00221 int cwi;
00222 const float *cr = params.FindFloat("cropwindow", &cwi);
00223 if (cr && cwi == 4) {
00224 crop[0] = Clamp(min(cr[0], cr[1]), 0., 1.);
00225 crop[1] = Clamp(max(cr[0], cr[1]), 0., 1.);
00226 crop[2] = Clamp(min(cr[2], cr[3]), 0., 1.);
00227 crop[3] = Clamp(max(cr[2], cr[3]), 0., 1.);
00228 }
00229 int writeFrequency = params.FindOneInt("writefrequency", -1);
00230
00231 return new ImageFilm(xres, yres, filter, crop,
00232 filename, premultiplyAlpha, writeFrequency);
00233 }