1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkOSPRayMaterialHelpers.cpp
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkOSPRayMaterialHelpers.h"
17 #include "vtkImageData.h"
18 #include "vtkOSPRayMaterialLibrary.h"
19 #include "vtkOSPRayRendererNode.h"
20 #include "vtkProperty.h"
21 #include "vtkTexture.h"
22
23 #include "RTWrapper/RTWrapper.h"
24
25 #include <limits>
26
27 //------------------------------------------------------------------------------
NewTexture2D(RTW::Backend * backend,const osp::vec2i & size,const OSPTextureFormat type,void * data,const uint32_t _flags)28 OSPTexture vtkOSPRayMaterialHelpers::NewTexture2D(RTW::Backend* backend, const osp::vec2i& size,
29 const OSPTextureFormat type, void* data, const uint32_t _flags)
30 {
31 auto texture = ospNewTexture("texture2d");
32 if (texture == nullptr)
33 {
34 return nullptr;
35 }
36
37 auto flags = _flags; // because the input value is declared const, use a copy
38
39 OSPDataType dataType = OSP_UNKNOWN;
40 if (type == OSP_TEXTURE_R32F)
41 {
42 dataType = OSP_FLOAT;
43 }
44 else if (type == OSP_TEXTURE_RGB32F)
45 {
46 dataType = OSP_VEC3F;
47 }
48 else if (type == OSP_TEXTURE_RGBA32F)
49 {
50 dataType = OSP_VEC4F;
51 }
52 else if (type == OSP_TEXTURE_R8)
53 {
54 dataType = OSP_UCHAR;
55 }
56 else if (type == OSP_TEXTURE_RGB8 || type == OSP_TEXTURE_SRGB)
57 {
58 dataType = OSP_VEC3UC;
59 }
60 else if (type == OSP_TEXTURE_RGBA8 || type == OSP_TEXTURE_SRGBA)
61 {
62 dataType = OSP_VEC4UC;
63 }
64 else
65 {
66 throw std::runtime_error("vtkOSPRayMaterialHelpers::NewTexture2D: Unknown texture format");
67 }
68
69 #if defined(__GNUC__)
70 #pragma GCC diagnostic push
71 #pragma GCC diagnostic ignored "-Wextra"
72 #endif
73 auto data_handle = ospNewCopyData2D(data, dataType, size.x, size.y);
74 #if defined(__GNUC__)
75 #pragma GCC diagnostic pop
76 #endif
77
78 ospCommit(data_handle);
79 ospSetObject(texture, "data", data_handle);
80 ospRelease(data_handle);
81
82 ospSetInt(texture, "format", static_cast<int>(type));
83 if (flags & OSP_TEXTURE_FILTER_NEAREST)
84 {
85 ospSetInt(texture, "filter", OSP_TEXTURE_FILTER_NEAREST);
86 }
87 ospCommit(texture);
88
89 return texture;
90 }
91
92 //------------------------------------------------------------------------------
VTKToOSPTexture(RTW::Backend * backend,vtkImageData * vColorTextureMap,bool isSRGB)93 OSPTexture vtkOSPRayMaterialHelpers::VTKToOSPTexture(
94 RTW::Backend* backend, vtkImageData* vColorTextureMap, bool isSRGB)
95 {
96 if (backend == nullptr)
97 {
98 return OSPTexture2D();
99 }
100
101 int xsize = vColorTextureMap->GetExtent()[1] - vColorTextureMap->GetExtent()[0];
102 int ysize = vColorTextureMap->GetExtent()[3] - vColorTextureMap->GetExtent()[2];
103
104 if (xsize < 0 || ysize < 0)
105 {
106 return nullptr;
107 }
108 int scalartype = vColorTextureMap->GetScalarType();
109 int comps = vColorTextureMap->GetNumberOfScalarComponents();
110
111 OSPTexture t2d = nullptr;
112
113 if (scalartype == VTK_UNSIGNED_CHAR || scalartype == VTK_CHAR || scalartype == VTK_SIGNED_CHAR)
114 {
115 OSPTextureFormat formatSRGB[4] = { OSP_TEXTURE_L8, OSP_TEXTURE_LA8, OSP_TEXTURE_SRGB,
116 OSP_TEXTURE_SRGBA };
117 OSPTextureFormat formatLinear[4] = { OSP_TEXTURE_R8, OSP_TEXTURE_RGB8, OSP_TEXTURE_RGB8,
118 OSP_TEXTURE_RGBA8 };
119 std::vector<unsigned char> chars;
120
121 if ((!isSRGB && comps == 2) || comps > 4)
122 {
123 // no native formats, we need to copy the components to a 3 channels texture
124 chars.resize((xsize + 1) * (ysize + 1) * 3, 0);
125 unsigned char* oc = chars.data();
126 unsigned char* ptr =
127 reinterpret_cast<unsigned char*>(vColorTextureMap->GetScalarPointer(0, 0, 0));
128 for (int i = 0; i <= xsize; ++i)
129 {
130 for (int j = 0; j <= ysize; ++j)
131 {
132 for (int k = 0; k < comps && k < 3; k++)
133 {
134 oc[k] = ptr[k];
135 }
136 ptr += comps;
137 oc += 3;
138 }
139 }
140 comps = 3;
141 }
142
143 t2d = vtkOSPRayMaterialHelpers::NewTexture2D(backend, osp::vec2i{ xsize + 1, ysize + 1 },
144 isSRGB ? formatSRGB[comps - 1] : formatLinear[comps - 1],
145 chars.empty() ? vColorTextureMap->GetScalarPointer() : chars.data(),
146 OSP_TEXTURE_FILTER_NEAREST);
147 }
148 else if (scalartype == VTK_FLOAT)
149 {
150 OSPTextureFormat format[4] = { OSP_TEXTURE_R32F, OSP_TEXTURE_RGB32F, OSP_TEXTURE_RGB32F,
151 OSP_TEXTURE_RGBA32F };
152 std::vector<float> floats;
153 if (comps == 2 || comps > 4)
154 {
155 // no native formats, we need to copy the components to a 3 channels texture
156 floats.resize((xsize + 1) * (ysize + 1) * 3, 0);
157 float* of = floats.data();
158 for (int i = 0; i <= ysize; ++i)
159 {
160 for (int j = 0; j <= xsize; ++j)
161 {
162 for (int k = 0; k < comps && k < 3; k++)
163 {
164 of[k] = vColorTextureMap->GetScalarComponentAsFloat(j, i, 0, k);
165 }
166 of += 3;
167 }
168 }
169 comps = 3;
170 }
171 t2d = vtkOSPRayMaterialHelpers::NewTexture2D(backend, osp::vec2i{ xsize + 1, ysize + 1 },
172 format[comps - 1], floats.empty() ? vColorTextureMap->GetScalarPointer() : floats.data(),
173 OSP_TEXTURE_FILTER_NEAREST);
174 }
175 else
176 {
177 // All other types are converted to float
178 int newComps = comps;
179 OSPTextureFormat format[4] = { OSP_TEXTURE_R32F, OSP_TEXTURE_RGB32F, OSP_TEXTURE_RGB32F,
180 OSP_TEXTURE_RGBA32F };
181
182 if (comps == 2 || comps > 4)
183 {
184 newComps = 3;
185 }
186
187 float multiplier = 1.f;
188 float shift = 0.f;
189
190 // 16-bits integer are not supported yet in OSPRay
191 switch (scalartype)
192 {
193 case VTK_SHORT:
194 shift += std::numeric_limits<short>::min();
195 multiplier /= std::numeric_limits<unsigned short>::max();
196 break;
197 case VTK_UNSIGNED_SHORT:
198 multiplier /= std::numeric_limits<unsigned short>::max();
199 break;
200 default:
201 break;
202 }
203
204 std::vector<float> floats;
205 floats.resize((xsize + 1) * (ysize + 1) * newComps, 0);
206 float* of = floats.data();
207 for (int i = 0; i <= ysize; ++i)
208 {
209 for (int j = 0; j <= xsize; ++j)
210 {
211 for (int k = 0; k < newComps && k < comps; k++)
212 {
213 of[k] = (vColorTextureMap->GetScalarComponentAsFloat(j, i, 0, k) + shift) * multiplier;
214 }
215 of += newComps;
216 }
217 }
218 t2d = vtkOSPRayMaterialHelpers::NewTexture2D(backend, osp::vec2i{ xsize + 1, ysize + 1 },
219 format[newComps - 1], floats.data(), OSP_TEXTURE_FILTER_NEAREST);
220 }
221
222 if (t2d != nullptr)
223 {
224 ospCommit(t2d);
225 }
226
227 return t2d;
228 }
229
230 //------------------------------------------------------------------------------
MakeMaterials(vtkOSPRayRendererNode * orn,OSPRenderer oRenderer,std::map<std::string,OSPMaterial> & mats)231 void vtkOSPRayMaterialHelpers::MakeMaterials(
232 vtkOSPRayRendererNode* orn, OSPRenderer oRenderer, std::map<std::string, OSPMaterial>& mats)
233 {
234 vtkOSPRayMaterialLibrary* ml = vtkOSPRayRendererNode::GetMaterialLibrary(orn->GetRenderer());
235 if (!ml)
236 {
237 cout << "No material Library in this renderer." << endl;
238 return;
239 }
240 std::set<std::string> nicknames = ml->GetMaterialNames();
241 std::set<std::string>::iterator it = nicknames.begin();
242 while (it != nicknames.end())
243 {
244 OSPMaterial newmat = vtkOSPRayMaterialHelpers::MakeMaterial(orn, oRenderer, *it);
245 mats[*it] = newmat;
246 ++it;
247 }
248 }
249
250 //------------------------------------------------------------------------------
MakeMaterial(vtkOSPRayRendererNode * orn,OSPRenderer oRenderer,std::string nickname)251 OSPMaterial vtkOSPRayMaterialHelpers::MakeMaterial(
252 vtkOSPRayRendererNode* orn, OSPRenderer oRenderer, std::string nickname)
253 {
254 RTW::Backend* backend = orn->GetBackend();
255 OSPMaterial oMaterial;
256 vtkOSPRayMaterialLibrary* ml = vtkOSPRayRendererNode::GetMaterialLibrary(orn->GetRenderer());
257 if (!ml)
258 {
259 vtkGenericWarningMacro("No material Library in this renderer. Using obj by default.");
260 return NewMaterial(orn, oRenderer, "obj");
261 }
262
263 const auto& dic = vtkOSPRayMaterialLibrary::GetParametersDictionary();
264
265 std::string implname = ml->LookupImplName(nickname);
266
267 if (dic.find(implname) != dic.end())
268 {
269 oMaterial = NewMaterial(orn, oRenderer, implname);
270
271 const auto& paramList = dic.at(implname);
272 for (auto param : paramList)
273 {
274 switch (param.second)
275 {
276 case vtkOSPRayMaterialLibrary::ParameterType::BOOLEAN:
277 {
278 auto values = ml->GetDoubleShaderVariable(nickname, param.first);
279 if (values.size() == 1)
280 {
281 ospSetInt(oMaterial, param.first.c_str(), static_cast<int>(values[0]));
282 }
283 }
284 break;
285 case vtkOSPRayMaterialLibrary::ParameterType::FLOAT:
286 case vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT:
287 {
288 auto values = ml->GetDoubleShaderVariable(nickname, param.first);
289 if (values.size() == 1)
290 {
291 ospSetFloat(oMaterial, param.first.c_str(), static_cast<float>(values[0]));
292 }
293 }
294 break;
295 case vtkOSPRayMaterialLibrary::ParameterType::FLOAT_DATA:
296 {
297 auto values = ml->GetDoubleShaderVariable(nickname, param.first);
298 if (!values.empty())
299 {
300 std::vector<float> fvalues(values.begin(), values.end());
301 OSPData data = ospNewCopyData1D(fvalues.data(), OSP_VEC3F, fvalues.size() / 3);
302 ospSetObject(oMaterial, param.first.c_str(), data);
303 }
304 }
305 break;
306 case vtkOSPRayMaterialLibrary::ParameterType::VEC2:
307 {
308 auto values = ml->GetDoubleShaderVariable(nickname, param.first);
309 if (values.size() == 2)
310 {
311 std::vector<float> fvalues(values.begin(), values.end());
312 ospSetVec2f(oMaterial, param.first.c_str(), fvalues[0], fvalues[1]);
313 }
314 }
315 break;
316 case vtkOSPRayMaterialLibrary::ParameterType::VEC3:
317 case vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB:
318 {
319 auto values = ml->GetDoubleShaderVariable(nickname, param.first);
320 if (values.size() == 3)
321 {
322 std::vector<float> fvalues(values.begin(), values.end());
323 ospSetVec3f(oMaterial, param.first.c_str(), fvalues[0], fvalues[1], fvalues[2]);
324 }
325 }
326 break;
327 case vtkOSPRayMaterialLibrary::ParameterType::VEC4:
328 {
329 auto values = ml->GetDoubleShaderVariable(nickname, param.first);
330 if (values.size() == 4)
331 {
332 std::vector<float> fvalues(values.begin(), values.end());
333 ospSetVec4f(
334 oMaterial, param.first.c_str(), fvalues[0], fvalues[1], fvalues[2], fvalues[3]);
335 }
336 }
337 break;
338 case vtkOSPRayMaterialLibrary::ParameterType::TEXTURE:
339 {
340 vtkTexture* texname = ml->GetTexture(nickname, param.first);
341 if (texname)
342 {
343 vtkImageData* vColorTextureMap = vtkImageData::SafeDownCast(texname->GetInput());
344 OSPTexture t2d = vtkOSPRayMaterialHelpers::VTKToOSPTexture(backend, vColorTextureMap);
345 ospSetObject(oMaterial, param.first.c_str(), static_cast<OSPTexture>(t2d));
346 ospRelease(t2d);
347 }
348 }
349 break;
350 default:
351 break;
352 }
353 }
354 }
355 else
356 {
357 vtkGenericWarningMacro(
358 "Warning: unrecognized material \"" << implname.c_str() << "\", using a default obj");
359 return NewMaterial(orn, oRenderer, "obj");
360 }
361
362 ospCommit(oMaterial);
363 return oMaterial;
364 }
365
366 //------------------------------------------------------------------------------
NewMaterial(vtkOSPRayRendererNode * orn,OSPRenderer oRenderer,std::string ospMatName)367 OSPMaterial vtkOSPRayMaterialHelpers::NewMaterial(
368 vtkOSPRayRendererNode* orn, OSPRenderer oRenderer, std::string ospMatName)
369 {
370 RTW::Backend* backend = orn->GetBackend();
371 OSPMaterial result = nullptr;
372
373 if (backend == nullptr)
374 return result;
375
376 (void)oRenderer;
377 const std::string rendererType = vtkOSPRayRendererNode::GetRendererType(orn->GetRenderer());
378 result = ospNewMaterial(rendererType.c_str(), ospMatName.c_str());
379
380 if (!result)
381 {
382 vtkGenericWarningMacro(
383 "OSPRay failed to create material: " << ospMatName << ". Trying obj instead.");
384 result = ospNewMaterial(rendererType.c_str(), "obj");
385 }
386
387 ospCommit(result);
388 return result;
389 }
390