1 #pragma once
2 
3 #include "vtkLogger.h"
4 
5 #include "../Types.h"
6 #include "OSPRayMDL.h"
7 #include "Texture.h"
8 
9 #include <VisRTX.h>
10 #include <cassert>
11 #include <set>
12 #include <sstream>
13 #include <string>
14 
15 namespace RTW
16 {
17     class Material : public Object
18     {
19         friend class Geometry;
20 
21     public:
Material(const std::string & type)22         Material(const std::string& type) : Object(RTW_MATERIAL), type(type)
23 
24         {
25             VisRTX::Context* rtx = VisRTX_GetContext();
26 
27             /*
28              * Basic material
29              */
30             if (this->type == "obj" || this->type == "luminous")
31             {
32                 this->material = rtx->CreateBasicMaterial();
33             }
34 
35             /*
36              * MDL material
37              */
38             else
39             {
40                 //OSPRay 2.0 name backward compatibility.
41                 if (this->type == "alloy")
42                     this->type = "Alloy";
43                 else if (this->type == "carPaint")
44                     this->type = "CarPaint";
45                 else if (this->type == "glass")
46                     this->type = "Glass";
47                 else if (this->type == "metal")
48                     this->type = "Metal";
49                 else if (this->type == "metallicPaint")
50                     this->type = "MetallicPaint";
51                 else if (this->type == "obj")
52                     this->type = "OBJMaterial";
53                 else if (this->type == "principled")
54                     this->type = "Principled";
55                 else if (this->type == "thinGlass")
56                     this->type = "ThinGlass";
57 
58                 const std::string materialname = "::ospray::" + this->type;
59                 try
60                 {
61                     this->material = rtx->CreateMDLMaterial(materialname.c_str(), (char*)OSPRay_mdl, (uint32_t) sizeof(OSPRay_mdl), 0, nullptr, VisRTX::CompilationType::INSTANCE);
62                 }
63                 catch(const std::exception&)
64                 {
65                     vtkLogF(ERROR, "VisRTX Error: CreateMDLMaterial failed! Falling back to BasicMaterial.");
66                     this->material = nullptr;
67                 }
68                 if (!this->material)
69                 {
70                     this->material = rtx->CreateBasicMaterial();
71                 }
72             }
73             assert(this->material != nullptr);
74         }
75 
~Material()76         ~Material()
77         {
78             this->material->Release();
79         }
80 
Commit()81         void Commit() override
82         {
83             assert(this->material != nullptr);
84 
85             /*
86              * OBJMaterial (Basic material)
87              */
88             if (this->type == "obj" && this->material->GetType() == VisRTX::MaterialType::BASIC)
89             {
90                 VisRTX::BasicMaterial* basicMaterial = dynamic_cast<VisRTX::BasicMaterial*>(this->material);
91                 assert(basicMaterial);
92                 if (!basicMaterial)
93                 {
94                     return;
95                 }
96 
97                 //this->PrintAllParameters();
98 
99                 basicMaterial->SetDiffuse(this->GetVec3f({ "kd", "Kd" }, VisRTX::Vec3f(0.8f, 0.8f, 0.8f)));
100                 basicMaterial->SetSpecular(this->GetVec3f({ "ks", "Ks" }, VisRTX::Vec3f(0.0f, 0.0f, 0.0f)));
101                 basicMaterial->SetShininess(this->GetFloat({ "ns", "Ns" }, 10.0f));
102                 basicMaterial->SetOpacity(this->GetFloat({ "d", "alpha" }, 1.0f));
103                 basicMaterial->SetTransparencyFilter(this->GetVec3f({ "tf", "Tf" }, VisRTX::Vec3f(0.0f, 0.0f, 0.0f)));
104 
105                 Texture* diffuseTex = this->GetObject<Texture>({ "map_Kd", "map_kd" });
106                 if (diffuseTex)
107                     basicMaterial->SetDiffuseTexture(diffuseTex->texture);
108 
109                 Texture* specularTex = this->GetObject<Texture>({ "map_Ks", "map_ks" });
110                 if (specularTex)
111                     basicMaterial->SetSpecularTexture(specularTex->texture);
112 
113                 Texture* shininessTex = this->GetObject<Texture>({ "map_Ns", "map_ns" });
114                 if (shininessTex)
115                     basicMaterial->SetShininessTexture(shininessTex->texture);
116 
117                 Texture* opacityTex = this->GetObject<Texture>({ "map_d", "map_alpha" });
118                 if (opacityTex)
119                     basicMaterial->SetOpacityTexture(opacityTex->texture);
120 
121                 Texture* bumpTex = this->GetObject<Texture>({ "map_Bump", "map_bump" });
122                 if (bumpTex)
123                     basicMaterial->SetBumpMapTexture(bumpTex->texture);
124             }
125 
126             /*
127              * Luminous (Basic material)
128              */
129             else if (this->type == "luminous" && this->material->GetType() == VisRTX::MaterialType::BASIC)
130             {
131                 VisRTX::BasicMaterial* basicMaterial = dynamic_cast<VisRTX::BasicMaterial*>(this->material);
132                 assert(basicMaterial);
133                 if (!basicMaterial)
134                 {
135                     return;
136                 }
137                 basicMaterial->SetEmissive(this->GetVec3f({ "color" }, VisRTX::Vec3f(0.0f, 0.0f, 0.0f)));
138                 basicMaterial->SetLuminosity(this->GetFloat({ "intensity" }, 0.0f));
139             }
140 
141             /*
142              * Others (MDL material)
143              */
144             else if (this->material->GetType() == VisRTX::MaterialType::MDL)
145             {
146                 VisRTX::MDLMaterial* mdlMaterial = dynamic_cast<VisRTX::MDLMaterial*>(this->material);
147                 assert(mdlMaterial);
148                 if (!mdlMaterial)
149                 {
150                     return;
151                 }
152 
153                 std::set<std::string> ospparams_current = this->GetAllParameters();
154 
155 #define PRINT_MATERIAL_PARAMETERS 0
156 #if PRINT_MATERIAL_PARAMETERS
157                 static std::set<std::string> mdltypes_printed;
158                 if (mdltypes_printed.find(this->type) == mdltypes_printed.end())
159                 {
160                     std::vector<std::string> availableParams;
161                     for (uint32_t i = 0; i < mdlMaterial->GetParameterCount(); ++i)
162                     {
163                         availableParams.push_back(mdlMaterial->GetParameterName(i));
164                     }
165 
166                     for (const auto &parameter : availableParams)
167                     {
168                         std::string parameterType;
169                         switch (mdlMaterial->GetParameterType(parameter.c_str()))
170                         {
171                         case VisRTX::ParameterType::NONE:
172                             parameterType = "none"; break;
173                         case VisRTX::ParameterType::COLOR:
174                             parameterType = "color"; break;
175                         case VisRTX::ParameterType::DOUBLE:
176                             parameterType = "double"; break;
177                         case VisRTX::ParameterType::FLOAT:
178                             parameterType = "float"; break;
179                         case VisRTX::ParameterType::INT:
180                             parameterType = "int"; break;
181                         case VisRTX::ParameterType::BOOL:
182                             parameterType = "bool"; break;
183                         case VisRTX::ParameterType::TEXTURE:
184                             parameterType = "texture"; break;
185                         }
186                         std::stringstream logStrBuf;
187                         logStrBuf << "(mdl) " << this->type << ": " << parameterType << " " << parameter;
188                         vtkLogF(INFO, "%s", logStrBuf.str().c_str());
189                     }
190                     mdltypes_printed.insert(this->type);
191                 }
192 
193 
194                 static std::set<std::string> ospparams_printed;
195 
196                 for (auto param : ospparams_current)
197                 {
198                     std::string complete = this->type + ": " + param;
199                     if (ospparams_printed.find(complete) == ospparams_printed.end())
200                     {
201                         vtkLogF(INFO, "(osp) %s", complete.c_str());
202                         ospparams_printed.insert(complete);
203                     }
204                 }
205 #endif //PRINT_MATERIAL_PARAMETERS
206 
207 #define WARN_NOT_IMPLEMENTED() vtkLogF(WARNING, "Warning: type \"%s\" not implemented (Material: %s, %s)", paramType.c_str(), this->type.c_str(), paramName.c_str());
208 
209                 for (const std::string &param : ospparams_current)
210                 {
211                     std::string paramType, paramName;
212                     {
213                         std::istringstream iss(param);
214                         iss >> paramType;
215                         iss >> paramName;
216                     }
217 
218                     //getters for osp materials require a vector of names
219                     std::vector<std::string> names;
220                     names.push_back(paramName);
221 
222                     //rename parameters if needed (osp name -> mdl name)
223 
224                     static const std::map<std::pair<std::string, std::string>, std::string> renameMap
225                     {
226                         { { "obj", "map_kd" }, "map_Kd"},
227                         { { "obj", "map_bump" }, "map_Bump"},
228                         { { "Glass", "etaInside" }, "eta"},
229                         { { "obj", "alpha" }, "d"},
230                         { { "ThinGlass", "transmission" }, "attenuationColor"}
231                     };
232 
233                     // explicit renames first
234                     auto rename_it = renameMap.find(std::make_pair(this->type, paramName));
235                     if (rename_it != renameMap.end())
236                     {
237                         paramName = rename_it->second;
238                     }
239                     else
240                     {
241                         //replace "...Map" with "map_..."
242                         const std::string ospSuffix = "Map";
243                         const std::string mdlPrefix = "map_";
244                         if (paramName.length() >= ospSuffix.length()
245                             && paramName.compare(paramName.length() - ospSuffix.length(),
246                                 ospSuffix.length(), ospSuffix) == 0)
247                         {
248                             std::string name =
249                                 paramName.substr(0, paramName.length() - ospSuffix.length());
250                             paramName = mdlPrefix + name;
251                         }
252                     }
253 
254                     //exceptions first, e.g. spectra; then handle parameters by type
255                     if (paramName == std::string("ior") && paramType == std::string("object"))
256                     {
257                         Data* iorData = this->GetObject<Data>(names);
258                         assert(iorData->GetElementDataType() == RTW_VEC3F);
259 
260                         if (iorData->GetElementDataType() != RTW_VEC3F)
261                         {
262                             vtkLogF(ERROR, "Error: unexpected data type in ior object");
263                             return;
264                         }
265 
266                         const unsigned n_input = iorData->GetNumElements();
267 
268                         const VisRTX::Vec3f *input = (const VisRTX::Vec3f*)iorData->GetData();
269 
270                         static const unsigned spectrum_size = 8;
271                         static const float wavelength_begin = 430.f;
272                         static const float wavelength_spacing = 35.f;
273 
274                         float eta[spectrum_size], k[spectrum_size];
275 
276                         //subsample ior array
277                         unsigned iinput = 0u, iprev = 0u;
278                         for (unsigned iwl = 0u; iwl < spectrum_size; iwl++)
279                         {
280                             const float currentwl = wavelength_begin + (float)iwl * wavelength_spacing;
281                             for (; iinput < n_input - 1 && input[iinput].x < currentwl; ++iinput)
282                             {
283                                 iprev = iinput;
284                             }
285                             if (input[iprev].x == input[iinput].x)
286                             {
287                                 eta[iwl] = input[iprev].y;
288                                 k[iwl] = input[iprev].z;
289                             }
290                             else
291                             {
292                                 const float t = (currentwl - input[iprev].x) / (input[iinput].x - input[iprev].x);
293                                 eta[iwl] = (1.f - t) * input[iprev].y + t * input[iinput].y;
294                                 k[iwl] = (1.f - t) * input[iprev].z + t * input[iinput].z;
295                             }
296                         }
297 
298                         //response functions
299                         static const float response_sRGB_r[spectrum_size] =
300                         {
301                             0.0598548,
302                             -0.0234574,
303                             -0.220138,
304                             -0.238902,
305                             0.316327,
306                             0.738315,
307                             0.323302,
308                             0.0446981
309                         };
310 
311                         static const float response_sRGB_g[spectrum_size] =
312                         {
313                             -0.0567346,
314                             -0.0160361,
315                             0.223861,
316                             0.531185,
317                             0.337221,
318                             0.0149718,
319                             -0.0296053,
320                             -0.00486239
321                         };
322 
323                         static const float response_sRGB_b[spectrum_size] =
324                         {
325                             0.420693,
326                             0.616597,
327                             0.0796766,
328                             -0.0496266,
329                             -0.0473149,
330                             -0.0167536,
331                             -0.00295686,
332                             -0.000314818
333                         };
334 
335                         //apply response functions to convert to RGB
336                         VisRTX::Vec3f eta3(0.f, 0.f, 0.f), k3(0.f, 0.f, 0.f);
337                         for (unsigned iwl = 0u; iwl < spectrum_size; ++iwl)
338                         {
339                             VisRTX::Vec3f response(response_sRGB_r[iwl], response_sRGB_g[iwl], response_sRGB_b[iwl]);
340 
341                             eta3.x += response.x * eta[iwl];
342                             eta3.y += response.y * eta[iwl];
343                             eta3.z += response.z * eta[iwl];
344                             k3.x += response.x * k[iwl];
345                             k3.y += response.y * k[iwl];
346                             k3.z += response.z * k[iwl];
347                         }
348 
349                         mdlMaterial->SetParameterColor("eta", eta3);
350                         mdlMaterial->SetParameterColor("k", k3);
351                     }
352                     else if (paramType == std::string("string"))
353                     {
354                         std::string ospParam = this->GetString(names);
355                         WARN_NOT_IMPLEMENTED();
356                     }
357                     else if (paramType == std::string("object"))
358                     {
359                         Texture* ospParam = this->GetObject<Texture>(names);
360                         if (ospParam)
361                         {
362                             mdlMaterial->SetParameterTexture(paramName.c_str(), ospParam->texture);
363                         }
364                         else
365                         {
366                             vtkLogF(WARNING, "Object \"%s\" of material type \"%s\" is not a texture.", paramName.c_str(), this->type.c_str());
367                         }
368                     }
369                     else if (paramType == std::string("int1"))
370                     {
371                         int ospParam = this->GetInt(names);
372 
373                         if (mdlMaterial->GetParameterType(paramName.c_str()) == VisRTX::ParameterType::BOOL)
374                         {
375                             mdlMaterial->SetParameterBool(paramName.c_str(), ospParam > 0);
376                         }
377                         else
378                         {
379                             mdlMaterial->SetParameterInt(paramName.c_str(), ospParam);
380                         }
381                     }
382                     else if (paramType == std::string("float1"))
383                     {
384                         float ospParam = this->GetFloat(names);
385 
386                         if (mdlMaterial->GetParameterType(paramName.c_str()) == VisRTX::ParameterType::BOOL)
387                         {
388                             mdlMaterial->SetParameterBool(paramName.c_str(), ospParam > 0.0f);
389                         }
390                         else
391                         {
392                             mdlMaterial->SetParameterFloat(paramName.c_str(), ospParam);
393                         }
394                     }
395                     else if (paramType == std::string("float2"))
396                     {
397                         VisRTX::Vec2f ospParam = this->GetVec2f(names);
398                         WARN_NOT_IMPLEMENTED();
399                     }
400                     else if (paramType == std::string("int3"))
401                     {
402                         VisRTX::Vec3i ospParam = this->GetVec3i(names);
403                         WARN_NOT_IMPLEMENTED();
404                     }
405                     else if (paramType == std::string("float3"))
406                     {
407                         VisRTX::Vec3f ospParam = this->GetVec3f(names);
408                         mdlMaterial->SetParameterColor(paramName.c_str(), ospParam);
409                     }
410                     else if (paramType == std::string("float4"))
411                     {
412                         VisRTX::Vec4f ospParam = this->GetVec4f(names);
413                         WARN_NOT_IMPLEMENTED();
414                     }
415                     else
416                     {
417                         WARN_NOT_IMPLEMENTED();
418                     }
419                 }
420 
421                 mdlMaterial->Compile();
422                 }
423             }
424 
425     private:
426         std::string type;
427         VisRTX::Material* material = nullptr;
428         };
429     }
430