00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef _LUXRAYS_SDL_MATERIAL_H
00023 #define _LUXRAYS_SDL_MATERIAL_H
00024
00025 #include <vector>
00026
00027 #include "luxrays/utils/core/exttrianglemesh.h"
00028 #include "luxrays/utils/sdl/mc.h"
00029
00030 namespace luxrays { namespace sdl {
00031
00032 class Scene;
00033
00034 enum MaterialType {
00035 MATTE, AREALIGHT, MIRROR, MATTEMIRROR, GLASS, METAL, MATTEMETAL,
00036 ARCHGLASS, ALLOY
00037 };
00038
00039 class Material {
00040 public:
00041 virtual ~Material() { }
00042
00043 virtual MaterialType GetType() const = 0;
00044
00045 virtual bool IsLightSource() const = 0;
00046 virtual bool IsDiffuse() const = 0;
00047 virtual bool IsSpecular() const = 0;
00048 virtual bool IsShadowTransparent() const { return false; }
00049
00050 virtual Spectrum GetSahdowTransparency() const {
00051 throw std::runtime_error("Internal error, called Material::GetSahdowTransparency()");
00052 }
00053 };
00054
00055 class LightMaterial : public Material {
00056 public:
00057 bool IsLightSource() const { return true; }
00058 bool IsDiffuse() const { return false; }
00059 bool IsSpecular() const { return false; }
00060
00061 virtual Spectrum Le(const ExtMesh *mesh, const unsigned triIndex, const Vector &wo) const = 0;
00062 };
00063
00064 class AreaLightMaterial : public LightMaterial {
00065 public:
00066 AreaLightMaterial(const Spectrum &col) { gain = col; }
00067
00068 MaterialType GetType() const { return AREALIGHT; }
00069
00070 Spectrum Le(const ExtMesh *mesh, const unsigned triIndex, const Vector &wo) const {
00071 Normal sampleN = mesh->GetNormal(triIndex, 0);
00072
00073 if (Dot(sampleN, wo) <= 0.f)
00074 return Spectrum();
00075
00076 if (mesh->HasColors())
00077 return mesh->GetColor(triIndex) * gain;
00078 else
00079 return gain;
00080 }
00081
00082 const Spectrum &GetGain() const { return gain; }
00083
00084 private:
00085 Spectrum gain;
00086 };
00087
00088 class SurfaceMaterial : public Material {
00089 public:
00090 bool IsLightSource() const { return false; }
00091
00092 virtual Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const = 0;
00093 virtual Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N,
00094 const Normal &shadeN, const float u0, const float u1, const float u2,
00095 const bool onlySpecular, float *pdf, bool &specularBounce) const = 0;
00096 };
00097
00098 class MatteMaterial : public SurfaceMaterial {
00099 public:
00100 MatteMaterial(const Spectrum &col) {
00101 Kd = col;
00102 KdOverPI = Kd * INV_PI;
00103 }
00104
00105 MaterialType GetType() const { return MATTE; }
00106
00107 bool IsDiffuse() const { return true; }
00108 bool IsSpecular() const { return false; }
00109
00110 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00111 return KdOverPI;
00112 }
00113
00114 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00115 const float u0, const float u1, const float u2, const bool onlySpecular,
00116 float *pdf, bool &specularBounce) const {
00117 if (onlySpecular) {
00118 *pdf = 0.f;
00119 return Spectrum();
00120 }
00121
00122 Vector dir = CosineSampleHemisphere(u0, u1);
00123 *pdf = dir.z * INV_PI;
00124
00125 Vector v1, v2;
00126 CoordinateSystem(Vector(shadeN), &v1, &v2);
00127
00128 dir = Vector(
00129 v1.x * dir.x + v2.x * dir.y + shadeN.x * dir.z,
00130 v1.y * dir.x + v2.y * dir.y + shadeN.y * dir.z,
00131 v1.z * dir.x + v2.z * dir.y + shadeN.z * dir.z);
00132
00133 (*wi) = dir;
00134
00135 const float dp = Dot(shadeN, *wi);
00136
00137 if (dp <= 0.0001f) {
00138 *pdf = 0.f;
00139 return Spectrum();
00140 }
00141 *pdf /= dp;
00142
00143 specularBounce = false;
00144
00145 return KdOverPI;
00146 }
00147
00148 const Spectrum &GetKd() const { return Kd; }
00149
00150 private:
00151 Spectrum Kd, KdOverPI;
00152 };
00153
00154 class MirrorMaterial : public SurfaceMaterial {
00155 public:
00156 MirrorMaterial(const Spectrum &refl, bool reflSpecularBounce) {
00157 Kr = refl;
00158 reflectionSpecularBounce = reflSpecularBounce;
00159 }
00160
00161 MaterialType GetType() const { return MIRROR; }
00162
00163 bool IsDiffuse() const { return false; }
00164 bool IsSpecular() const { return true; }
00165
00166 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00167 throw std::runtime_error("Internal error, called MirrorMaterial::f()");
00168 }
00169
00170 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00171 const float u0, const float u1, const float u2, const bool onlySpecular,
00172 float *pdf, bool &specularBounce) const {
00173 const Vector dir = -wo;
00174 const float dp = Dot(shadeN, dir);
00175 (*wi) = dir - (2.f * dp) * Vector(shadeN);
00176
00177 specularBounce = reflectionSpecularBounce;
00178 *pdf = 1.f;
00179
00180 return Kr;
00181 }
00182
00183 const Spectrum &GetKr() const { return Kr; }
00184
00185 private:
00186 Spectrum Kr;
00187 bool reflectionSpecularBounce;
00188 };
00189
00190 class MatteMirrorMaterial : public SurfaceMaterial {
00191 public:
00192 MatteMirrorMaterial(const Spectrum &col, const Spectrum refl, bool reflSpecularBounce) :
00193 matte(col), mirror(refl, reflSpecularBounce) {
00194 matteFilter = matte.GetKd().Filter();
00195 mirrorFilter = mirror.GetKr().Filter();
00196 totFilter = matteFilter + mirrorFilter;
00197
00198 mattePdf = matteFilter / totFilter;
00199 mirrorPdf = mirrorFilter / totFilter;
00200 }
00201
00202 MaterialType GetType() const { return MATTEMIRROR; }
00203
00204 bool IsDiffuse() const { return true; }
00205 bool IsSpecular() const { return true; }
00206
00207 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00208 return matte.f(wo, wi, N) * mattePdf;
00209 }
00210
00211 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00212 const float u0, const float u1, const float u2, const bool onlySpecular,
00213 float *pdf, bool &specularBounce) const {
00214 const float comp = u2 * totFilter;
00215
00216 if (onlySpecular || (comp > matteFilter)) {
00217 const Spectrum f = mirror.Sample_f(wo, wi, N, shadeN, u0, u1, u2, onlySpecular, pdf, specularBounce);
00218 *pdf *= mirrorPdf;
00219
00220 return f;
00221 } else {
00222 const Spectrum f = matte.Sample_f(wo, wi, N, shadeN, u0, u1, u2, onlySpecular, pdf, specularBounce);
00223 *pdf *= mattePdf;
00224
00225 return f;
00226 }
00227 }
00228
00229 private:
00230 MatteMaterial matte;
00231 MirrorMaterial mirror;
00232 float matteFilter, mirrorFilter, totFilter, mattePdf, mirrorPdf;
00233 };
00234
00235 class GlassMaterial : public SurfaceMaterial {
00236 public:
00237 GlassMaterial(const Spectrum &refl, const Spectrum &refrct, const float outsideIorFact,
00238 const float iorFact, bool reflSpecularBounce, bool transSpecularBounce) {
00239 Krefl = refl;
00240 Krefrct = refrct;
00241 ousideIor = outsideIorFact;
00242 ior = iorFact;
00243
00244 reflectionSpecularBounce = reflSpecularBounce;
00245 transmitionSpecularBounce = transSpecularBounce;
00246
00247 const float nc = ousideIor;
00248 const float nt = ior;
00249 const float a = nt - nc;
00250 const float b = nt + nc;
00251 R0 = a * a / (b * b);
00252 }
00253
00254 MaterialType GetType() const { return GLASS; }
00255
00256 bool IsDiffuse() const { return false; }
00257 bool IsSpecular() const { return true; }
00258
00259 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00260 throw std::runtime_error("Internal error, called GlassMaterial::f()");
00261 }
00262
00263 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00264 const float u0, const float u1, const float u2, const bool onlySpecular,
00265 float *pdf, bool &specularBounce) const {
00266 const Vector rayDir = -wo;
00267 const Vector reflDir = rayDir - (2.f * Dot(N, rayDir)) * Vector(N);
00268
00269
00270 const bool into = (Dot(N, shadeN) > 0);
00271
00272 const float nc = ousideIor;
00273 const float nt = ior;
00274 const float nnt = into ? (nc / nt) : (nt / nc);
00275 const float ddn = Dot(rayDir, shadeN);
00276 const float cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn);
00277
00278
00279 if (cos2t < 0.f) {
00280 (*wi) = reflDir;
00281 *pdf = 1.f;
00282 specularBounce = reflectionSpecularBounce;
00283
00284 return Krefl;
00285 }
00286
00287 const float kk = (into ? 1.f : -1.f) * (ddn * nnt + sqrtf(cos2t));
00288 const Vector nkk = kk * Vector(N);
00289 const Vector transDir = Normalize(nnt * rayDir - nkk);
00290
00291 const float c = 1.f - (into ? -ddn : Dot(transDir, N));
00292
00293 const float Re = R0 + (1.f - R0) * c * c * c * c * c;
00294 const float Tr = 1.f - Re;
00295 const float P = .25f + .5f * Re;
00296
00297 if (Tr == 0.f) {
00298 if (Re == 0.f) {
00299 *pdf = 0.f;
00300 return Spectrum();
00301 } else {
00302 (*wi) = reflDir;
00303 *pdf = 1.f;
00304 specularBounce = reflectionSpecularBounce;
00305
00306 return Krefl;
00307 }
00308 } else if (Re == 0.f) {
00309 (*wi) = transDir;
00310 *pdf = 1.f;
00311 specularBounce = transmitionSpecularBounce;
00312
00313 return Krefrct;
00314 } else if (u0 < P) {
00315 (*wi) = reflDir;
00316 *pdf = P / Re;
00317 specularBounce = reflectionSpecularBounce;
00318
00319 return Krefl;
00320 } else {
00321 (*wi) = transDir;
00322 *pdf = (1.f - P) / Tr;
00323 specularBounce = transmitionSpecularBounce;
00324
00325 return Krefrct;
00326 }
00327 }
00328
00329 const Spectrum &GetKrefl() const { return Krefl; }
00330 const Spectrum &GetKrefrct() const { return Krefrct; }
00331
00332 private:
00333 Spectrum Krefl, Krefrct;
00334 float ousideIor, ior;
00335 float R0;
00336 bool reflectionSpecularBounce, transmitionSpecularBounce;
00337 };
00338
00339 class MetalMaterial : public SurfaceMaterial {
00340 public:
00341 MetalMaterial(const Spectrum &refl, const float exp, bool reflSpecularBounce) {
00342 Kr = refl;
00343 exponent = 1.f / (exp + 1.f);
00344 reflectionSpecularBounce = reflSpecularBounce;
00345 }
00346
00347 MaterialType GetType() const { return METAL; }
00348
00349 bool IsDiffuse() const { return false; }
00350 bool IsSpecular() const { return true; }
00351
00352 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00353 throw std::runtime_error("Internal error, called MetalMaterial::f()");
00354 }
00355
00356 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00357 const float u0, const float u1, const float u2, const bool onlySpecular,
00358 float *pdf, bool &specularBounce) const {
00359 (*wi) = GlossyReflection(wo, exponent, shadeN, u0, u1);
00360
00361 if (Dot(*wi, shadeN) > 0.f) {
00362 specularBounce = reflectionSpecularBounce;
00363 *pdf = 1.f;
00364
00365 return Kr;
00366 } else {
00367 *pdf = 0.f;
00368
00369 return Spectrum();
00370 }
00371 }
00372
00373 const Spectrum &GetKr() const { return Kr; }
00374
00375 static Vector GlossyReflection(const Vector &wo, const float exponent,
00376 const Normal &shadeN, const float u0, const float u1) {
00377 const float phi = 2.f * M_PI * u0;
00378 const float cosTheta = powf(1.f - u1, exponent);
00379 const float sinTheta = sqrtf(1.f - cosTheta * cosTheta);
00380 const float x = cosf(phi) * sinTheta;
00381 const float y = sinf(phi) * sinTheta;
00382 const float z = cosTheta;
00383
00384 const Vector dir = -wo;
00385 const float dp = Dot(shadeN, dir);
00386 const Vector w = dir - (2.f * dp) * Vector(shadeN);
00387
00388 Vector u;
00389 if (fabsf(shadeN.x) > .1f) {
00390 const Vector a(0.f, 1.f, 0.f);
00391 u = Cross(a, w);
00392 } else {
00393 const Vector a(1.f, 0.f, 0.f);
00394 u = Cross(a, w);
00395 }
00396 u = Normalize(u);
00397 Vector v = Cross(w, u);
00398
00399 return x * u + y * v + z * w;
00400 }
00401
00402 private:
00403 Spectrum Kr;
00404 float exponent;
00405 bool reflectionSpecularBounce;
00406 };
00407
00408 class MatteMetalMaterial : public SurfaceMaterial {
00409 public:
00410 MatteMetalMaterial(const Spectrum &col, const Spectrum refl, const float exp, bool reflSpecularBounce) :
00411 matte(col), metal(refl, exp, reflSpecularBounce) {
00412 matteFilter = matte.GetKd().Filter();
00413 metalFilter = metal.GetKr().Filter();
00414 totFilter = matteFilter + metalFilter;
00415
00416 mattePdf = matteFilter / totFilter;
00417 metalPdf = metalFilter / totFilter;
00418 }
00419
00420 MaterialType GetType() const { return MATTEMETAL; }
00421
00422 bool IsDiffuse() const { return true; }
00423 bool IsSpecular() const { return true; }
00424
00425 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00426 return matte.f(wo, wi, N) * mattePdf;
00427 }
00428
00429 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00430 const float u0, const float u1, const float u2, const bool onlySpecular,
00431 float *pdf, bool &specularBounce) const {
00432 const float comp = u2 * totFilter;
00433
00434 if (onlySpecular || (comp > matteFilter)) {
00435 const Spectrum f = metal.Sample_f(wo, wi, N, shadeN, u0, u1, u2, onlySpecular, pdf, specularBounce);
00436 *pdf *= metalPdf;
00437
00438 return f;
00439 } else {
00440 const Spectrum f = matte.Sample_f(wo, wi, N, shadeN, u0, u1, u2, onlySpecular, pdf, specularBounce);
00441 *pdf *= mattePdf;
00442
00443 return f;
00444 }
00445 }
00446
00447 private:
00448 MatteMaterial matte;
00449 MetalMaterial metal;
00450 float matteFilter, metalFilter, totFilter, mattePdf, metalPdf;
00451 };
00452
00453 class ArchGlassMaterial : public SurfaceMaterial {
00454 public:
00455 ArchGlassMaterial(const Spectrum &refl, const Spectrum &refrct,
00456 bool reflSpecularBounce, bool transSpecularBounce) {
00457 Krefl = refl;
00458 Ktrans = refrct;
00459
00460 reflectionSpecularBounce = reflSpecularBounce;
00461 transmitionSpecularBounce = transSpecularBounce;
00462
00463 reflFilter = Krefl.Filter();
00464 transFilter = Ktrans.Filter();
00465 totFilter = reflFilter + transFilter;
00466
00467 reflPdf = reflFilter / totFilter;
00468 transPdf = transFilter / totFilter;
00469 }
00470
00471 MaterialType GetType() const { return ARCHGLASS; }
00472
00473 bool IsDiffuse() const { return false; }
00474 bool IsSpecular() const { return true; }
00475 bool IsShadowTransparent() const { return true; }
00476
00477 Spectrum GetSahdowTransparency() const {
00478 return Ktrans;
00479 }
00480
00481 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00482 throw std::runtime_error("Internal error, called ArchGlassMaterial::f()");
00483 }
00484
00485 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00486 const float u0, const float u1, const float u2, const bool onlySpecular,
00487 float *pdf, bool &specularBounce) const {
00488
00489 const bool into = (Dot(N, shadeN) > 0);
00490
00491 if (!into) {
00492
00493 (*wi) = -wo;
00494 *pdf = 1.f;
00495 specularBounce = reflectionSpecularBounce;
00496
00497 return Ktrans;
00498 } else {
00499
00500 const float comp = u0 * totFilter;
00501 if (comp > transFilter) {
00502 const Vector mwo = -wo;
00503 (*wi) = mwo - (2.f * Dot(N, mwo)) * Vector(N);
00504 *pdf = reflPdf;
00505 specularBounce = reflectionSpecularBounce;
00506
00507 return Krefl;
00508 } else {
00509 (*wi) = -wo;
00510 *pdf = transPdf;
00511 specularBounce = transmitionSpecularBounce;
00512
00513 return Ktrans;
00514 }
00515 }
00516 }
00517
00518 const Spectrum &GetKrefl() const { return Krefl; }
00519 const Spectrum &GetKrefrct() const { return Ktrans; }
00520
00521 private:
00522 Spectrum Krefl, Ktrans;
00523 float reflFilter, transFilter, totFilter, reflPdf, transPdf;
00524 bool reflectionSpecularBounce, transmitionSpecularBounce;
00525 };
00526
00527 class AlloyMaterial : public SurfaceMaterial {
00528 public:
00529 AlloyMaterial(const Spectrum &col, const Spectrum &refl,
00530 const float exp, const float schlickTerm, bool reflSpecularBounce) {
00531 Krefl = refl;
00532 Kdiff = col;
00533 KdiffOverPI = Kdiff * INV_PI;
00534 R0 = schlickTerm;
00535 exponent = 1.f / (exp + 1.f);
00536
00537 reflectionSpecularBounce = reflSpecularBounce;
00538 }
00539
00540 MaterialType GetType() const { return ALLOY; }
00541
00542 bool IsDiffuse() const { return true; }
00543 bool IsSpecular() const { return true; }
00544
00545 Spectrum f(const Vector &wo, const Vector &wi, const Normal &N) const {
00546
00547 const float c = 1.f - Dot(wo, N);
00548 const float Re = R0 + (1.f - R0) * c * c * c * c * c;
00549
00550 const float P = .25f + .5f * Re;
00551
00552 return KdiffOverPI * (1.f - Re) / (1.f - P);
00553 }
00554
00555 Spectrum Sample_f(const Vector &wo, Vector *wi, const Normal &N, const Normal &shadeN,
00556 const float u0, const float u1, const float u2, const bool onlySpecular,
00557 float *pdf, bool &specularBounce) const {
00558
00559 const float c = 1.f - Dot(wo, shadeN);
00560 const float Re = R0 + (1.f - R0) * c * c * c * c * c;
00561
00562 const float P = .25f + .5f * Re;
00563
00564 if (onlySpecular || (u2 < P)) {
00565 (*wi) = MetalMaterial::GlossyReflection(wo, exponent, shadeN, u0, u1);
00566 *pdf = P / Re;
00567 specularBounce = reflectionSpecularBounce;
00568
00569 return Re * Krefl;
00570 } else {
00571 Vector dir = CosineSampleHemisphere(u0, u1);
00572 *pdf = dir.z * INV_PI;
00573
00574 Vector v1, v2;
00575 CoordinateSystem(Vector(shadeN), &v1, &v2);
00576
00577 dir = Vector(
00578 v1.x * dir.x + v2.x * dir.y + shadeN.x * dir.z,
00579 v1.y * dir.x + v2.y * dir.y + shadeN.y * dir.z,
00580 v1.z * dir.x + v2.z * dir.y + shadeN.z * dir.z);
00581
00582 (*wi) = dir;
00583
00584 const float dp = Dot(shadeN, *wi);
00585
00586 if (dp <= 0.0001f) {
00587 *pdf = 0.f;
00588 return Spectrum();
00589 }
00590 *pdf /= dp;
00591
00592 const float iRe = 1.f - Re;
00593 *pdf *= (1.f - P) / iRe;
00594 specularBounce = false;
00595
00596 return iRe * Kdiff;
00597
00598 }
00599 }
00600
00601 const Spectrum &GetKrefl() const { return Krefl; }
00602
00603 private:
00604 Spectrum Krefl;
00605 Spectrum Kdiff, KdiffOverPI;
00606 float exponent;
00607 float R0;
00608 bool reflectionSpecularBounce;
00609 };
00610
00611 } }
00612
00613 #endif