Material.cpp
Go to the documentation of this file.00001 /**<!--------------------------------------------------------------------> 00002 @file Material.cpp 00003 @author Travis Fischer (fisch0920@gmail.com) 00004 @author Matthew Jacobs (jacobs.mh@gmail.com) 00005 @date Fall 2008 00006 00007 @brief 00008 Abstract representation of a surface Material, defined without respect 00009 to the underlying surface (loose coupling between Shapes and Materials 00010 from the point-of-view of a Material, but all Shapes know about their 00011 surface Material). Materials subclass PropertyMap, and it is through this 00012 interface that Material properties may be set (ex: diffuse color, 00013 texture/bump/color map(s), index of refraction of interior volume, etc.) 00014 00015 Reflectivity, emittance, and sensor response (BSDFs, Emitters, and 00016 Sensors respectively) are three properties of a material that are defined 00017 at a single point on a surface. A Material encapsulates BSDF, Emitter, 00018 and Sensor properties defined over its surface, where specific instances of 00019 BSDF, Emitter, and Sensor are allowed to have their inputs vary with 00020 respect to position along the surface. In this respect, Materials 00021 represent a mapping from surface position to associated BSDF, Emitter, and 00022 Sensor functions, where the underlying functions themselves remain constant 00023 along the surface, and only the inputs vary among the different instances / 00024 surface points. For example, a Material may have a DiffuseBSDF over its 00025 entire surface, but a specific DiffuseBSDF instance obtained by getBSDF or 00026 implicitly in initSurfacePoint (which fills in the SurfacePoint's BSDF), is 00027 allowed to have its 'kd' parameter (diffuse albedo) vary with respect to 00028 the given surface point via lookup in an associated 'kd' texture map 00029 defined over the UV coordinates of the surface. 00030 <!-------------------------------------------------------------------->**/ 00031 00032 #include "Material.h" 00033 #include <materials.h> 00034 #include <filters.h> 00035 00036 #include <ResourceManager.h> 00037 #include <Camera.h> 00038 00039 #include <GL/gl.h> 00040 #include <QtCore> 00041 00042 // initialize static members of Material 00043 SurfacePoint Material::s_nullSurfacePoint; 00044 Emitter *Material::s_nullEmitter = new NullEmitter(Material::s_nullSurfacePoint); 00045 Sensor *Material::s_nullSensor = new NullSensor (Material::s_nullSurfacePoint); 00046 00047 Material::~Material() { 00048 safeDelete(m_filter); 00049 } 00050 00051 void Material::init() { 00052 const std::string &filter = getValue<std::string>("filter", "triangle"); 00053 00054 m_filter = KernelFilter::create(filter, *this); 00055 00056 m_bsdf = getValue<const std::string>("bsdf", m_bsdf); 00057 m_emitter = getValue<const std::string>("emitter", m_emitter); 00058 m_bumpMap = getValue<const std::string>("bumpMap", m_bumpMap); 00059 00060 m_repeatU = getValue<real_t>("repeatU", m_repeatU); 00061 m_repeatV = getValue<real_t>("repeatV", m_repeatV); 00062 m_bumpIntensity = getValue<real_t>("bumpIntensity", m_bumpIntensity); 00063 } 00064 00065 BSDF *Material::getBSDF(SurfacePoint &pt) { 00066 BSDF *bsdf = NULL; 00067 00068 if (m_bsdf == "diffuse") { 00069 bsdf = new DiffuseBSDF(pt, this); 00070 } else if (m_bsdf == "dielectric") { 00071 bsdf = new DielectricBSDF(pt, this); 00072 } else if (m_bsdf == "modifiedPhong" || m_bsdf == "phong") { 00073 bsdf = new ModifiedPhongBSDF(pt, this); 00074 } else if (m_bsdf == "absorbent") { 00075 bsdf = new AbsorbentBSDF(pt, this); 00076 } else if (m_bsdf == "specular") { 00077 (*this)["transparency"] = 0.0; 00078 bsdf = new DielectricBSDF(pt, this); 00079 } else if (m_bsdf == "transmissive") { 00080 (*this)["transparency"] = 1.0; 00081 bsdf = new DielectricBSDF(pt, this); 00082 } else { 00083 cerr << "invalid material (BSDF type): " << m_bsdf << endl; 00084 ASSERT(0 && "Found Invalid Material (BSDF type)"); 00085 return NULL; 00086 } 00087 00088 bsdf->init(); 00089 return bsdf; 00090 } 00091 00092 bool Material::isEmitter() { 00093 return (m_emitter != "null"); 00094 } 00095 00096 Emitter *Material::getEmitter(SurfacePoint &pt) { 00097 Emitter *emitter = NULL; 00098 00099 // standard area light; emittance distribution restricted by surface normal 00100 if (m_emitter == "oriented") { 00101 emitter = new OrientedEmitter(pt, this); 00102 } else if (m_emitter == "omni" || m_emitter == "point") { 00103 emitter = new OmniEmitter(pt, this); 00104 } else if (m_emitter == "environment") { 00105 emitter = new EnvironmentMap(this); 00106 } else { 00107 ASSERT(m_emitter == "null" && "Found Invalid Material (Emitter type)"); 00108 00109 return Material::s_nullEmitter; 00110 } 00111 00112 emitter->init(); 00113 return emitter; 00114 } 00115 00116 Emitter *Material::getEmitter() { 00117 return getEmitter(s_nullSurfacePoint); 00118 } 00119 00120 Sensor *Material::getSensor(SurfacePoint &pt) { 00121 Sensor *sensor = Material::s_nullSensor; 00122 Camera *camera = NULL; 00123 00124 // TODO: make this not dependent on Camera... 00125 try { 00126 camera = dynamic_cast<Camera*>(pt.shape); 00127 } catch(std::bad_cast&) { } 00128 00129 if (camera) { 00130 sensor = new Sensor(pt, this); 00131 sensor->init(); 00132 } 00133 00134 return sensor; 00135 } 00136 00137 void Material::preview(Shape *shape) { 00138 SurfacePoint pt; 00139 pt.shape = shape; 00140 00141 if (isEmitter()) { 00142 Emitter *emitter = getEmitter(pt); 00143 emitter->preview(shape); 00144 00145 if (emitter != Material::s_nullEmitter) 00146 safeDelete(emitter); 00147 } 00148 00149 BSDF *bsdf = getBSDF(pt); 00150 bsdf->preview(shape); 00151 00152 safeDelete(bsdf); 00153 } 00154 00155 void Material::initSurfacePoint(SurfacePoint &pt) { 00156 safeDelete(pt.bsdf); 00157 00158 // TODO: abstract this out into SurfacePoint or Material 00159 if (pt.emitter != Material::s_nullEmitter) 00160 safeDelete(pt.emitter); 00161 if (pt.sensor != Material::s_nullSensor) 00162 safeDelete(pt.sensor); 00163 00164 _initShadingNormal(pt); 00165 00166 pt.bsdf = getBSDF(pt); 00167 pt.emitter = getEmitter(pt); 00168 pt.sensor = getSensor(pt); 00169 00170 const SpectralSampleSet &ior = 00171 getSpectralSampleSet("ior", IndexOfRefraction::AIR, pt); 00172 00173 const unsigned index = Random::sampleInt(0, ior.getN()); 00174 pt.ior2 = ior[index].value; 00175 } 00176 00177 void Material::_initShadingNormal(SurfacePoint &pt) { 00178 // default to geometric normal if no bumpmap was specified 00179 if (m_bumpMap == "") { 00180 pt.normalS = pt.normalG; 00181 return; 00182 } 00183 00184 // load or access cached version of bumpmap image 00185 const ImagePtr &image = ResourceManager::getImage(m_bumpMap); 00186 00187 // if image failed to load successfully, default to geometric normal 00188 if (!image) { 00189 pt.normalS = pt.normalG; 00190 return; 00191 } 00192 00193 // calculate bumpmap base coordinates 00194 const int width = image->getWidth(); 00195 const int height = image->getHeight(); 00196 00197 const real_t s = pt.uv.u * m_repeatU; 00198 const real_t t = pt.uv.v * m_repeatV; 00199 const int x = (int)(CAP((s - floor(s)) * width, 0, width - 1)); 00200 const int y = (int)(CAP((t - floor(t)) * height, 0, height - 1)); 00201 00202 // compute discrete partial derivatives 00203 const real_t xGrad = 00204 image->getLuminance(y, x - (x > 0)) - 00205 image->getLuminance(y, x + (x < width - 1)); 00206 const real_t yGrad = 00207 image->getLuminance(y - (y > 0), x) - 00208 image->getLuminance(y + (y < height - 1), x); 00209 00210 if (EQ(xGrad, 0) && EQ(yGrad, 0)) { 00211 pt.normalS = pt.normalG; 00212 return; 00213 } 00214 00215 // construct orthonormal basis given geometric normal at samplepoint 00216 Vector3 N = pt.normalG; 00217 Vector3 U, V; 00218 00219 N.getOrthonormalBasis(U, V); 00220 00221 // scaleFactor modifies the intensity or magnitude of the bumps 00222 pt.normalS = (N + m_bumpIntensity * (xGrad * U + yGrad * V)).getNormalized(); 00223 } 00224 00225 SpectralSampleSet Material::getSpectralSampleSet(const std::string &key, 00226 const SpectralSampleSet &defaultValue, 00227 const SurfacePoint &pt) 00228 { 00229 if (!contains(key)) 00230 return boost::any_cast<const SpectralSampleSet&>((*this)[key] = defaultValue); 00231 00232 return getSpectralSampleSet(key, pt); 00233 } 00234 00235 SpectralSampleSet Material::getSpectralSampleSet(const std::string &key, 00236 const real_t &defaultValue, 00237 const SurfacePoint &pt) 00238 { 00239 if (!contains(key)) { 00240 return boost::any_cast<const SpectralSampleSet&>((*this)[key] = 00241 SpectralSampleSet::fill(defaultValue)); 00242 } 00243 00244 return getSpectralSampleSet(key, pt); 00245 } 00246 00247 SpectralSampleSet Material::getSpectralSampleSet(const std::string &key, 00248 const std::string &defaultValue, 00249 const SurfacePoint &pt) 00250 { 00251 if (!contains(key)) 00252 (*this)[key] = defaultValue; 00253 00254 return getSpectralSampleSet(key, pt); 00255 } 00256 00257 SpectralSampleSet Material::getSpectralSampleSet(const std::string &key, 00258 const SurfacePoint &pt) 00259 { 00260 const boost::any &value = (*this)[key]; 00261 00262 if (value.type() == typeid(SpectralSampleSet)) { 00263 return boost::any_cast<SpectralSampleSet>(value); 00264 } else if (value.type() == typeid(std::string)) { 00265 const std::string &fileName = boost::any_cast<std::string>(value); 00266 const ImagePtr &image = ResourceManager::getImage(fileName); 00267 00268 if (image) 00269 return SpectralSampleSet(getSample(image, pt.uv)); 00270 } else if (value.type() == typeid(real_t)) { 00271 return SpectralSampleSet::fill(boost::any_cast<real_t>(value)); 00272 } else { 00273 ASSERT(0 && "invalid spectrum type"); 00274 } 00275 00276 return SpectralSampleSet::fill(0.7); 00277 } 00278 00279 RgbaHDR Material::getSample(const ImagePtr &image, const UV &uv) 00280 { 00281 ASSERT(image); 00282 00283 if (NULL == m_filter) { 00284 init(); 00285 00286 ASSERT(m_filter); 00287 } 00288 00289 const unsigned width = image->getWidth(); 00290 const unsigned height = image->getHeight(); 00291 00292 const real_t s = uv.u * m_repeatU; 00293 const real_t t = uv.v * m_repeatV; 00294 const real_t x = CAP((s - floor(s)) * width, 0, width - 1); 00295 const real_t y = CAP((t - floor(t)) * height, 0, height - 1); 00296 00297 return m_filter->apply(image.get(), x, y); 00298 } 00299
Generated on 28 Feb 2009 for Milton by
1.5.6