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 "texture.h"
00027 #include "paramset.h"
00028 #include "sampling.h"
00029 #include "shape.h"
00030
00031 enum { NONE, SUPERSAMPLE, CLOSEDFORM } aaMethod;
00032
00033 template <class T> class Checkerboard2D : public Texture<T> {
00034 public:
00035
00036 Checkerboard2D(TextureMapping2D *m,
00037 Reference<Texture<T> > c1,
00038 Reference<Texture<T> > c2,
00039 const string &aa) {
00040 mapping = m;
00041 tex1 = c1;
00042 tex2 = c2;
00043
00044 if (aa == "none") aaMethod = NONE;
00045 else if (aa == "supersample") aaMethod = SUPERSAMPLE;
00046 else if (aa == "closedform") aaMethod = CLOSEDFORM;
00047 else {
00048 Warning("Anti-aliasing mode \"%s\" not understood "
00049 "by Checkerboard2D, defaulting"
00050 "to \"supersample\"", aa.c_str());
00051 aaMethod = SUPERSAMPLE;
00052 }
00053 }
00054 ~Checkerboard2D() {
00055 delete mapping;
00056 }
00057 T Evaluate(const DifferentialGeometry &dg) const {
00058 float s, t, dsdx, dtdx, dsdy, dtdy;
00059 mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy);
00060 if (aaMethod == CLOSEDFORM) {
00061
00062
00063 float ds = max(fabsf(dsdx), fabsf(dsdy));
00064 float dt = max(fabsf(dtdx), fabsf(dtdy));
00065 float s0 = s - ds, s1 = s + ds;
00066 float t0 = t - dt, t1 = t + dt;
00067 if (Floor2Int(s0) == Floor2Int(s1) &&
00068 Floor2Int(t0) == Floor2Int(t1)) {
00069
00070 if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
00071 return tex1->Evaluate(dg);
00072 return tex2->Evaluate(dg);
00073 }
00074
00075 #define BUMPINT(x) \
00076 (Floor2Int((x)/2) + \
00077 2.f * max((x/2)-Floor2Int(x/2) - .5f, 0.f))
00078 float sint = (BUMPINT(s1) - BUMPINT(s0)) / (2.f * ds);
00079 float tint = (BUMPINT(t1) - BUMPINT(t0)) / (2.f * dt);
00080 float area2 = sint + tint - 2.f * sint * tint;
00081 if (ds > 1.f || dt > 1.f)
00082 area2 = .5f;
00083 return (1.f - area2) * tex1->Evaluate(dg) +
00084 area2 * tex2->Evaluate(dg);
00085 }
00086 else if (aaMethod == SUPERSAMPLE) {
00087
00088 #define SQRT_SAMPLES 4
00089 #define N_SAMPLES (SQRT_SAMPLES * SQRT_SAMPLES)
00090 float samples[2*N_SAMPLES];
00091 StratifiedSample2D(samples, SQRT_SAMPLES, SQRT_SAMPLES);
00092 T value = 0.;
00093 float filterSum = 0.;
00094 for (int i = 0; i < N_SAMPLES; ++i) {
00095
00096 float dx = samples[2*i] - 0.5f;
00097 float dy = samples[2*i+1] - 0.5f;
00098 DifferentialGeometry dgs = dg;
00099 dgs.p += dx * dgs.dpdx + dy * dgs.dpdy;
00100 dgs.u += dx * dgs.dudx + dy * dgs.dudy;
00101 dgs.v += dx * dgs.dvdx + dy * dgs.dvdy;
00102 dgs.dudx /= N_SAMPLES;
00103 dgs.dudy /= N_SAMPLES;
00104 dgs.dvdx /= N_SAMPLES;
00105 dgs.dvdy /= N_SAMPLES;
00106
00107 float ss, ts, dsdxs, dtdxs, dsdys, dtdys;
00108 mapping->Map(dgs, &ss, &ts, &dsdxs, &dtdxs, &dsdys, &dtdys);
00109 float wt = expf(-2.f * (dx*dx + dy*dy));
00110 filterSum += wt;
00111 if ((Floor2Int(ss) + Floor2Int(ts)) % 2 == 0)
00112 value += wt * tex1->Evaluate(dgs);
00113 else
00114 value += wt * tex2->Evaluate(dgs);
00115 }
00116 return value / filterSum;
00117 #undef N_SAMPLES // NOBOOK
00118 }
00119
00120 if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
00121 return tex1->Evaluate(dg);
00122 return tex2->Evaluate(dg);
00123 }
00124 private:
00125
00126 Reference<Texture<T> > tex1, tex2;
00127 TextureMapping2D *mapping;
00128 };
00129 template <class T> class Checkerboard3D : public Texture<T> {
00130 public:
00131
00132 Checkerboard3D(TextureMapping3D *m,
00133 Reference<Texture<T> > c1,
00134 Reference<Texture<T> > c2) {
00135 mapping = m;
00136 tex1 = c1;
00137 tex2 = c2;
00138 }
00139 T Evaluate(const DifferentialGeometry &dg) const {
00140
00141 #define N_SAMPLES 4
00142 float samples[2*N_SAMPLES*N_SAMPLES];
00143 StratifiedSample2D(samples, N_SAMPLES, N_SAMPLES);
00144 T value = 0.;
00145 float filterSum = 0.;
00146 for (int i = 0; i < N_SAMPLES*N_SAMPLES; ++i) {
00147
00148 float dx = samples[2*i] - 0.5f;
00149 float dy = samples[2*i+1] - 0.5f;
00150 DifferentialGeometry dgs = dg;
00151 dgs.p += dx * dgs.dpdx + dy * dgs.dpdy;
00152 dgs.u += dx * dgs.dudx + dy * dgs.dudy;
00153 dgs.v += dx * dgs.dvdx + dy * dgs.dvdy;
00154 dgs.dudx /= N_SAMPLES;
00155 dgs.dudy /= N_SAMPLES;
00156 dgs.dvdx /= N_SAMPLES;
00157 dgs.dvdy /= N_SAMPLES;
00158
00159 Vector dPPdx, dPPdy;
00160 Point PP = mapping->Map(dgs, &dPPdx, &dPPdy);
00161 float wt = expf(-2.f * (dx*dx + dy*dy));
00162 filterSum += wt;
00163 if ((Floor2Int(PP.x) + Floor2Int(PP.y) + Floor2Int(PP.z)) % 2 == 0)
00164 value += wt * tex1->Evaluate(dgs);
00165 else
00166 value += wt * tex2->Evaluate(dgs);
00167 }
00168 return value / filterSum;
00169 }
00170 private:
00171
00172 Reference<Texture<T> > tex1, tex2;
00173 TextureMapping3D *mapping;
00174 };
00175
00176 extern "C" DLLEXPORT Texture<float> * CreateFloatTexture(const Transform &tex2world,
00177 const TextureParams &tp) {
00178 int dim = tp.FindInt("dimension", 2);
00179 if (dim != 2 && dim != 3) {
00180 Error("%d dimensional checkerboard texture not supported", dim);
00181 return NULL;
00182 }
00183 Reference<Texture<float> > tex1 = tp.GetFloatTexture("tex1", 1.f);
00184 Reference<Texture<float> > tex2 = tp.GetFloatTexture("tex2", 0.f);
00185 if (dim == 2) {
00186
00187 TextureMapping2D *map = NULL;
00188 string type = tp.FindString("mapping");
00189 if (type == "" || type == "uv") {
00190 float su = tp.FindFloat("uscale", 1.);
00191 float sv = tp.FindFloat("vscale", 1.);
00192 float du = tp.FindFloat("udelta", 0.);
00193 float dv = tp.FindFloat("vdelta", 0.);
00194 map = new UVMapping2D(su, sv, du, dv);
00195 }
00196 else if (type == "spherical") map = new SphericalMapping2D(tex2world.GetInverse());
00197 else if (type == "cylindrical") map = new CylindricalMapping2D(tex2world.GetInverse());
00198 else if (type == "planar")
00199 map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)),
00200 tp.FindVector("v2", Vector(0,1,0)),
00201 tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f));
00202 else {
00203 Error("2D texture mapping \"%s\" unknown", type.c_str());
00204 map = new UVMapping2D;
00205 }
00206 string aamode = tp.FindString("aamode");
00207 if (aamode == "") aamode = "closedform";
00208 return new Checkerboard2D<float>(map, tex1, tex2, aamode);
00209 }
00210 else {
00211
00212 TextureMapping3D *map = new IdentityMapping3D(tex2world);
00213 return new Checkerboard3D<float>(map, tex1, tex2);
00214 }
00215 }
00216
00217 extern "C" DLLEXPORT Texture<Spectrum> * CreateSpectrumTexture(const Transform &tex2world,
00218 const TextureParams &tp) {
00219 int dim = tp.FindInt("dimension", 2);
00220 if (dim != 2 && dim != 3) {
00221 Error("%d dimensional checkerboard texture not supported", dim);
00222 return NULL;
00223 }
00224 Reference<Texture<Spectrum> > tex1 = tp.GetSpectrumTexture("tex1", 1.f);
00225 Reference<Texture<Spectrum> > tex2 = tp.GetSpectrumTexture("tex2", 0.f);
00226 if (dim == 2) {
00227
00228 TextureMapping2D *map = NULL;
00229 string type = tp.FindString("mapping");
00230 if (type == "" || type == "uv") {
00231 float su = tp.FindFloat("uscale", 1.);
00232 float sv = tp.FindFloat("vscale", 1.);
00233 float du = tp.FindFloat("udelta", 0.);
00234 float dv = tp.FindFloat("vdelta", 0.);
00235 map = new UVMapping2D(su, sv, du, dv);
00236 }
00237 else if (type == "spherical") map = new SphericalMapping2D(tex2world.GetInverse());
00238 else if (type == "cylindrical") map = new CylindricalMapping2D(tex2world.GetInverse());
00239 else if (type == "planar")
00240 map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)),
00241 tp.FindVector("v2", Vector(0,1,0)),
00242 tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f));
00243 else {
00244 Error("2D texture mapping \"%s\" unknown", type.c_str());
00245 map = new UVMapping2D;
00246 }
00247 string aamode = tp.FindString("aamode");
00248 if (aamode == "") aamode = "closedform";
00249 return new Checkerboard2D<Spectrum>(map, tex1, tex2, aamode);
00250 }
00251 else {
00252
00253 TextureMapping3D *map = new IdentityMapping3D(tex2world);
00254 return new Checkerboard3D<Spectrum>(map, tex1, tex2);
00255 }
00256 }