From 48e92bf9000eeda6606183260834043de885113a Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sun, 21 Oct 2012 00:20:24 -0400 Subject: [PATCH] added material presets by Narasimhan et al. --- doc/main.bib | 12 ++++++ src/bsdfs/hk.cpp | 5 ++- src/librender/medium.cpp | 8 +++- src/librender/skdtree.cpp | 2 +- src/medium/homogeneous.cpp | 48 +++++++++++++-------- src/medium/materials.h | 85 ++++++++++++++++++++++++++++++-------- src/subsurface/dipole.cpp | 13 +++--- 7 files changed, 127 insertions(+), 46 deletions(-) diff --git a/doc/main.bib b/doc/main.bib index f81d6fcd..96b918dd 100644 --- a/doc/main.bib +++ b/doc/main.bib @@ -542,3 +542,15 @@ address = {New York, NY, USA}, } +@article{Narasimhan2006Acquiring, + author = {Narasimhan, Srinivasa G. and Gupta, Mohit and Donner, Craig and Ramamoorthi, Ravi and Nayar, Shree K. and Jensen, Henrik Wann}, + title = {Acquiring scattering properties of participating media by dilution}, + journal = {ACM Trans. Graph.}, + volume = {25}, + number = {3}, + month = jul, + year = {2006}, + pages = {1003--1012}, + publisher = {ACM}, + address = {New York, NY, USA} +} diff --git a/src/bsdfs/hk.cpp b/src/bsdfs/hk.cpp index 22485bca..b7521a44 100644 --- a/src/bsdfs/hk.cpp +++ b/src/bsdfs/hk.cpp @@ -114,8 +114,9 @@ MTS_NAMESPACE_BEGIN class HanrahanKrueger : public BSDF { public: HanrahanKrueger(const Properties &props) : BSDF(props) { - Spectrum sigmaS, sigmaA; - lookupMaterial(props, sigmaS, sigmaA, NULL); + Spectrum sigmaS, sigmaA, g; + lookupMaterial(props, sigmaS, sigmaA, g, NULL); + sigmaS *= Spectrum(1.0f) - g; /* Scattering coefficient of the layer */ m_sigmaS = new ConstantSpectrumTexture( diff --git a/src/librender/medium.cpp b/src/librender/medium.cpp index e40d225e..5c86832c 100644 --- a/src/librender/medium.cpp +++ b/src/librender/medium.cpp @@ -26,7 +26,13 @@ MTS_NAMESPACE_BEGIN Medium::Medium(const Properties &props) : NetworkedObject(props) { - lookupMaterial(props, m_sigmaS, m_sigmaA); + Spectrum g; + lookupMaterial(props, m_sigmaS, m_sigmaA, g); + + /* For now, ignore the anisotropy information of preset materials + and use the reduced scattering coefficient */ + m_sigmaS *= Spectrum(1.0f) - g; + m_sigmaT = m_sigmaA + m_sigmaS; } diff --git a/src/librender/skdtree.cpp b/src/librender/skdtree.cpp index aacd2a85..5de789e8 100644 --- a/src/librender/skdtree.cpp +++ b/src/librender/skdtree.cpp @@ -104,7 +104,7 @@ void ShapeKDTree::build() { } } Log(EDebug, "Finished -- took %i ms.", timer->getMilliseconds()); - Log(EDebug, ""); + Log(m_logLevel, ""); KDAssert(idx == primCount); #endif } diff --git a/src/medium/homogeneous.cpp b/src/medium/homogeneous.cpp index a8274414..2fdde4ae 100644 --- a/src/medium/homogeneous.cpp +++ b/src/medium/homogeneous.cpp @@ -99,27 +99,41 @@ MTS_NAMESPACE_BEGIN * * \begin{table}[h!] * \centering - * \begin{tabular}{>{\ttfamily}p{2cm}p{.8cm}>{\ttfamily}p{2cm}} + * \vspace{3mm} + * {\footnotesize + * \begin{tabular}{>{\ttfamily}p{3.8cm}p{.4cm}>{\ttfamily}p{3.8cm}p{.4cm}>{\ttfamily}p{3.8cm}} * \toprule - * \rmfamily \textbf{Name} && - * \rmfamily \textbf{Name} \\ - * \cmidrule{1-1} \cmidrule{3-3} - * apple&&potato\\ - * chicken1&&skimmilk\\ - * chicken2&&skin1\\ - * cream&&skin2\\ - * ketchup&&spectralon\\ - * marble&&wholemilk\\ + * \rmfamily \small\textbf{Name} && + * \rmfamily \small\textbf{Name} && + * \rmfamily \small\textbf{Name} \\ + * \cmidrule{1-1} \cmidrule{3-3} \cmidrule{5-5} + * Apple && Chicken1 && Chicken2 \\ + * Cream && Ketchup && Potato \\ + * Skimmilk && Skin1 && Skin2 \\ + * Spectralon && Wholemilk && \\ + * \cmidrule{1-1} \cmidrule{3-3} \cmidrule{5-5} + * Lowfat Milk && Gatorade && White Grapefruit Juice \\ + * Reduced Milk && Chardonnay && Shampoo \\ + * Regular Milk && White Zinfandel && Strawberry Shampoo \\ + * Espresso && Merlot && \mbox{Head \& Shoulders Shampoo} \\ + * Mint Mocha Coffee && Budweiser Beer && Lemon Tea Powder \\ + * Lowfat Soy Milk && Coors Light Beer && Orange Juice Powder \\ + * Regular Soy Milk && Clorox && Pink Lemonade Powder \\ + * Lowfat Chocolate Milk && Apple Juice && Cappuccino Powder \\ + * Regular Chocolate Milk && Cranberry Juice && Salt Powder \\ + * Coke && Grape Juice && Sugar Powder \\ + * Pepsi && Ruby Grapefruit Juice && Suisse Mocha \\ + * Sprite && && \\ * \bottomrule - * \end{tabular} - * \caption{ - * \label{tbl:medium-coefficients} - * This table lists all supported medium material presets. The - * values are from Jensen et al. \cite{Jensen2001Practical} using - * units of $\frac{1}{mm}$, so remember to set + * \end{tabular}} + * \caption{\label{tbl:medium-coefficients}This + * table lists all supported medium material presets. The + * top entries are from Jensen et al. \cite{Jensen2001Practical}, and the + * bottom ones are from Narasimhan et al. \cite{Narasimhan2006Acquiring}. + * They all use units of $\frac{1}{mm}$, so remember to set * \code{scale} appropriately when your scene is not * in units of millimeters. - * These material names can be used with the plugins + * These material presets can be used with the plugins * \pluginref{homogeneous},\ * \pluginref{dipole}, and \ * \pluginref{hk} diff --git a/src/medium/materials.h b/src/medium/materials.h index 882523dc..772eb63d 100644 --- a/src/medium/materials.h +++ b/src/medium/materials.h @@ -27,27 +27,66 @@ struct MaterialEntry { const char *name; Float sigmaS[3]; Float sigmaA[3]; + Float g[3]; Float eta; }; -/* Fitted data from "A Practical Model for Subsurface scattering" (Jensen et al.) */ static MaterialEntry materialData[] = { - { "apple", { 2.29f, 2.39f, 1.97f }, { 0.0030f, 0.0034f, 0.046f }, 1.3f }, - { "chicken1", { 0.15f, 0.21f, 0.38f }, { 0.0015f, 0.077f, 0.19f }, 1.3f }, - { "chicken2", { 0.19f, 0.25f, 0.32f }, { 0.0018f, 0.088f, 0.20f }, 1.3f }, - { "cream", { 7.38f, 5.47f, 3.15f }, { 0.0002f, 0.0028f, 0.0163f }, 1.3f }, - { "ketchup", { 0.18f, 0.07f, 0.03f }, { 0.061f, 0.97f, 1.45f }, 1.3f }, - { "marble", { 2.19f, 2.62f, 3.00f }, { 0.0021f, 0.0041f, 0.0071f }, 1.5f }, - { "potato", { 0.68f, 0.70f, 0.55f }, { 0.0024f, 0.0090f, 0.12f }, 1.3f }, - { "skimmilk", { 0.70f, 1.22f, 1.90f }, { 0.0014f, 0.0025f, 0.0142f }, 1.3f }, - { "skin1", { 0.74f, 0.88f, 1.01f }, { 0.032f, 0.17f, 0.48f }, 1.3f }, - { "skin2", { 1.09f, 1.59f, 1.79f }, { 0.013f, 0.070f, 0.145f }, 1.3f }, - { "spectralon", { 11.6f, 20.4f, 14.9f }, { 0.00f, 0.00f, 0.00f }, 1.3f }, - { "wholemilk", { 2.55f, 3.21f, 3.77f }, { 0.0011f, 0.0024f, 0.014f }, 1.3f }, - { NULL, { 0.00f, 0.00f, 0.00f }, { 0.00f, 0.00f, 0.00f }, 0.0f } + /* Fitted data from "A Practical Model for Subsurface scattering" (Jensen et al.). No anisotropy data available. */ + { "Apple", { 2.29f, 2.39f, 1.97f }, { 0.0030f, 0.0034f, 0.046f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Chicken1", { 0.15f, 0.21f, 0.38f }, { 0.0015f, 0.077f, 0.19f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Chicken2", { 0.19f, 0.25f, 0.32f }, { 0.0018f, 0.088f, 0.20f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Cream", { 7.38f, 5.47f, 3.15f }, { 0.0002f, 0.0028f, 0.0163f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Ketchup", { 0.18f, 0.07f, 0.03f }, { 0.061f, 0.97f, 1.45f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Marble", { 2.19f, 2.62f, 3.00f }, { 0.0021f, 0.0041f, 0.0071f }, { 1.0f, 1.0f, 1.0f }, 1.5f }, + { "Potato", { 0.68f, 0.70f, 0.55f }, { 0.0024f, 0.0090f, 0.12f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Skimmilk", { 0.70f, 1.22f, 1.90f }, { 0.0014f, 0.0025f, 0.0142f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Skin1", { 0.74f, 0.88f, 1.01f }, { 0.032f, 0.17f, 0.48f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Skin2", { 1.09f, 1.59f, 1.79f }, { 0.013f, 0.070f, 0.145f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Spectralon", { 11.6f, 20.4f, 14.9f }, { 0.00f, 0.00f, 0.00f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + { "Wholemilk", { 2.55f, 3.21f, 3.77f }, { 0.0011f, 0.0024f, 0.014f }, { 1.0f, 1.0f, 1.0f }, 1.3f }, + + /* From "Acquiring Scattering Properties of Participating Media by Dilution" + by Narasimhan, Gupta, Donner, Ramamoorthi, Nayar, Jensen (SIGGRAPH 2006) */ + { "Lowfat Milk", { 0.9124, 1.0744, 1.2492 }, { 0.0002, 0.0004, 0.0008 }, { 0.9320, 0.9020, 0.8590 }, 1.33f }, + { "Reduced Milk", { 1.0748, 1.2209, 1.3931 }, { 0.0002, 0.0004, 0.0010 }, { 0.8190, 0.7970, 0.7460 }, 1.33f }, + { "Regular Milk", { 1.1873, 1.3293, 1.4589 }, { 0.0001, 0.0003, 0.0013 }, { 0.7500, 0.7140, 0.6810 }, 1.33f }, + { "Espresso", { 0.2707, 0.2828, 0.2970 }, { 0.1669, 0.2287, 0.3078 }, { 0.9070, 0.8960, 0.8800 }, 1.33f }, + { "Mint Mocha Coffee", { 0.0916, 0.1081, 0.1460 }, { 0.0984, 0.1519, 0.2040 }, { 0.9100, 0.9070, 0.9140 }, 1.33f }, + { "Lowfat Soy Milk", { 0.1418, 0.1620, 0.2715 }, { 0.0001, 0.0005, 0.0025 }, { 0.8500, 0.8530, 0.8420 }, 1.33f }, + { "Regular Soy Milk", { 0.2433, 0.2714, 0.4563 }, { 0.0001, 0.0005, 0.0034 }, { 0.8730, 0.8580, 0.8320 }, 1.33f }, + { "Lowfat Chocolate Milk", { 0.4277, 0.4998, 0.5723 }, { 0.0005, 0.0016, 0.0068 }, { 0.9340, 0.9270, 0.9160 }, 1.33f }, + { "Regular Chocolate Milk", { 0.7352, 0.9142, 1.0588 }, { 0.0007, 0.0030, 0.0100 }, { 0.8620, 0.8380, 0.8060 }, 1.33f }, + { "Coke", { 0.0177, 0.0208, 0.0000 }, { 0.6966, 1.1480, 1.7169 }, { 0.9650, 0.9720, 0.9685 }, 1.33f }, + { "Pepsi", { 0.0058, 0.0141, 0.0000 }, { 0.6375, 0.9849, 1.4420 }, { 0.9260, 0.9790, 0.9525 }, 1.33f }, + { "Sprite", { 0.0069, 0.0089, 0.0089 }, { 0.1230, 0.1194, 0.1306 }, { 0.9430, 0.9530, 0.9520 }, 1.33f }, + { "Gatorade", { 0.2392, 0.2927, 0.3745 }, { 0.1617, 0.1258, 0.0579 }, { 0.9330, 0.9330, 0.9350 }, 1.33f }, + { "Chardonnay", { 0.0030, 0.0047, 0.0069 }, { 0.1547, 0.1701, 0.3443 }, { 0.9140, 0.9580, 0.9750 }, 1.33f }, + { "White Zinfandel", { 0.0031, 0.0048, 0.0066 }, { 0.1732, 0.2322, 0.2847 }, { 0.9190, 0.9430, 0.9720 }, 1.33f }, + { "Merlot", { 0.0053, 0.0000, 0.0000 }, { 0.7586, 1.6429, 1.9196 }, { 0.9740, 0.9740, 0.9740 }, 1.33f }, + { "Budweiser Beer", { 0.0037, 0.0069, 0.0074 }, { 0.1449, 0.3141, 0.7286 }, { 0.9170, 0.9560, 0.9820 }, 1.33f }, + { "Coors Light Beer", { 0.0027, 0.0055, 0.0000 }, { 0.0268, 0.0608, 0.1521 }, { 0.9180, 0.9660, 0.9420 }, 1.33f }, + { "Clorox", { 0.1425, 0.1723, 0.1928 }, { 0.0175, 0.0777, 0.1372 }, { 0.9120, 0.9050, 0.8920 }, 1.33f }, + { "Apple Juice", { 0.0201, 0.0243, 0.0323 }, { 0.1014, 0.1858, 0.4084 }, { 0.9470, 0.9490, 0.9450 }, 1.33f }, + { "Cranberry Juice", { 0.0128, 0.0155, 0.0196 }, { 0.2572, 0.6145, 0.8104 }, { 0.9470, 0.9510, 0.9740 }, 1.33f }, + { "Grape Juice", { 0.0072, 0.0000, 0.0000 }, { 0.5428, 1.2500, 1.5300 }, { 0.9610, 0.9610, 0.9610 }, 1.33f }, + { "Ruby Grapefruit Juice", { 0.1617, 0.1606, 0.1669 }, { 0.0896, 0.1911, 0.2636 }, { 0.9290, 0.9290, 0.9310 }, 1.33f }, + { "White Grapefruit Juice", { 0.3513, 0.3669, 0.5237 }, { 0.0096, 0.0131, 0.0395 }, { 0.5480, 0.5450, 0.5650 }, 1.33f }, + { "Shampoo", { 0.0104, 0.0114, 0.0147 }, { 0.0184, 0.0596, 0.0805 }, { 0.9100, 0.9050, 0.9200 }, 1.33f }, + { "Strawberry Shampoo", { 0.0028, 0.0032, 0.0033 }, { 0.0189, 0.0756, 0.0989 }, { 0.9270, 0.9350, 0.9940 }, 1.33f }, + { "Head & Shoulders Shampoo", { 0.2791, 0.2890, 0.3086 }, { 0.0883, 0.1637, 0.2125 }, { 0.9110, 0.8960, 0.8840 }, 1.33f }, + { "Lemon Tea Powder", { 0.0798, 0.0898, 0.1073 }, { 0.2602, 0.4902, 0.7727 }, { 0.9460, 0.9460, 0.9490 }, 1.33f }, + { "Orange Juice Powder", { 0.1928, 0.2132, 0.2259 }, { 0.1449, 0.3441, 0.7863 }, { 0.9190, 0.9180, 0.9220 }, 1.33f }, + { "Pink Lemonade Powder", { 0.1235, 0.1334, 0.1305 }, { 0.1165, 0.2366, 0.3195 }, { 0.9020, 0.9020, 0.9040 }, 1.33f }, + { "Cappuccino Powder", { 0.0654, 0.0882, 0.1568 }, { 0.1920, 0.2654, 0.3272 }, { 0.8490, 0.8430, 0.9260 }, 1.33f }, + { "Salt Powder", { 0.2485, 0.2822, 0.3216 }, { 0.5115, 0.5863, 0.6147 }, { 0.8020, 0.7930, 0.8210 }, 1.33f }, + { "Sugar Powder", { 0.0145, 0.0162, 0.0202 }, { 0.0650, 0.1597, 0.2578 }, { 0.9210, 0.9190, 0.9310 }, 1.33f }, + { "Suisse Mocha", { 0.3223, 0.3583, 0.4148 }, { 0.1875, 0.2893, 0.3796 }, { 0.9070, 0.8940, 0.8880 }, 1.33f }, + + { NULL, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, 0.0f } }; -static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum &sigmaA, Float *eta = NULL) { +static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum &sigmaA, Spectrum &g, Float *eta = NULL) { bool hasSigmaAS = props.hasProperty("sigmaS") || props.hasProperty("sigmaA"), hasSigmaTAlbedo = props.hasProperty("sigmaT") || props.hasProperty("albedo"), hasIOR = props.hasProperty("intIOR") || props.hasProperty("extIOR"), @@ -66,13 +105,13 @@ static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum & "sigmaT & albedo, but no other combinations!"); std::string material = - boost::to_lower_copy(props.getString("material", "skin1")); + boost::to_lower_copy(props.getString("material", "Skin1")); /* Start with a preset */ bool found = false; MaterialEntry *matEntry = materialData; while (matEntry->name) { - if (material == matEntry->name) { + if (material == boost::to_lower_copy(std::string(matEntry->name))) { sigmaS.fromLinearRGB( matEntry->sigmaS[0], matEntry->sigmaS[1], @@ -81,6 +120,10 @@ static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum & matEntry->sigmaA[0], matEntry->sigmaA[1], matEntry->sigmaA[2]); + g.fromLinearRGB( + matEntry->g[0], + matEntry->g[1], + matEntry->g[2]); sigmaS *= 100; sigmaA *= 100; if (eta) @@ -118,6 +161,12 @@ static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum & sigmaA = sigmaT - sigmaS; } + if (props.hasProperty("g")) + g = Spectrum(props.getFloat("g")); + + if (g.min() <= -1 || g.max() >= 1) + SLog(EError, "The anisotropy parameter 'g' must be in the range (-1, 1)!"); + if (eta && hasIOR) { /* Specifies the internal index of refraction at the interface */ Float intIOR = lookupIOR(props, "intIOR", "bk7"); @@ -137,7 +186,7 @@ static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum & sigmaA *= scale; std::ostringstream oss; - oss << "Medium parameters: sigmaS=" << sigmaS.toString() << ", sigmaA=" << sigmaA.toString(); + oss << "Medium parameters: sigmaS=" << sigmaS.toString() << ", sigmaA=" << sigmaA.toString() << ", g=" << g.average(); SLog(EDebug, "%s", oss.str().c_str()); } diff --git a/src/subsurface/dipole.cpp b/src/subsurface/dipole.cpp index ff467eb4..4865f488 100644 --- a/src/subsurface/dipole.cpp +++ b/src/subsurface/dipole.cpp @@ -289,18 +289,17 @@ public: m_quality = props.getFloat("quality", 0.2f); /* Asymmetry parameter of the phase function */ - m_g = props.getFloat("g", 0); m_ready = false; m_octreeResID = -1; - lookupMaterial(props, m_sigmaS, m_sigmaA, &m_eta); + lookupMaterial(props, m_sigmaS, m_sigmaA, m_g, &m_eta); } IsotropicDipole(Stream *stream, InstanceManager *manager) : Subsurface(stream, manager) { m_sigmaS = Spectrum(stream); m_sigmaA = Spectrum(stream); - m_g = stream->readFloat(); + m_g = Spectrum(stream); m_eta = stream->readFloat(); m_sampleMultiplier = stream->readFloat(); m_quality = stream->readFloat(); @@ -326,7 +325,7 @@ public: Subsurface::serialize(stream, manager); m_sigmaS.serialize(stream); m_sigmaA.serialize(stream); - stream->writeFloat(m_g); + m_g.serialize(stream); stream->writeFloat(m_eta); stream->writeFloat(m_sampleMultiplier); stream->writeFloat(m_quality); @@ -351,7 +350,7 @@ public: } void configure() { - m_sigmaSPrime = m_sigmaS * (1 - m_g); + m_sigmaSPrime = m_sigmaS * (Spectrum(1.0f) - m_g); m_sigmaTPrime = m_sigmaSPrime + m_sigmaA; /* Find the smallest mean-free path over all wavelengths */ @@ -466,8 +465,8 @@ public: MTS_DECLARE_CLASS() private: Float m_radius, m_sampleMultiplier; - Float m_Fdr, m_quality, m_g, m_eta; - Spectrum m_sigmaS, m_sigmaA; + Float m_Fdr, m_quality, m_eta; + Spectrum m_sigmaS, m_sigmaA, m_g; Spectrum m_sigmaTr, m_zr, m_zv; Spectrum m_sigmaSPrime, m_sigmaTPrime; ref m_octree;