1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkProperty.cxx
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 #include "vtkProperty.h"
16
17 #include "vtkActor.h"
18 #include "vtkInformation.h"
19 #include "vtkObjectFactory.h"
20 #include "vtkRenderWindow.h"
21 #include "vtkRenderer.h"
22 #include "vtkSmartPointer.h"
23 #include "vtkTexture.h"
24
25 #include <cstdlib>
26 #include <sstream>
27
28 #include <cmath>
29
30 #include <vtksys/SystemTools.hxx>
31
32 vtkCxxSetObjectMacro(vtkProperty, Information, vtkInformation);
33
34 //------------------------------------------------------------------------------
35 // Return nullptr if no override is supplied.
36 vtkObjectFactoryNewMacro(vtkProperty);
37
38 // Construct object with object color, ambient color, diffuse color,
39 // specular color, and edge color white; ambient coefficient=0; diffuse
40 // coefficient=0; specular coefficient=0; specular power=1; Gouraud shading;
41 // and surface representation. Backface and frontface culling are off.
vtkProperty()42 vtkProperty::vtkProperty()
43 {
44 // Really should initialize all colors including Color[3]
45 this->Color[0] = 1;
46 this->Color[1] = 1;
47 this->Color[2] = 1;
48
49 this->AmbientColor[0] = 1;
50 this->AmbientColor[1] = 1;
51 this->AmbientColor[2] = 1;
52
53 this->DiffuseColor[0] = 1;
54 this->DiffuseColor[1] = 1;
55 this->DiffuseColor[2] = 1;
56
57 this->SpecularColor[0] = 1;
58 this->SpecularColor[1] = 1;
59 this->SpecularColor[2] = 1;
60
61 this->EdgeColor[0] = 0;
62 this->EdgeColor[1] = 0;
63 this->EdgeColor[2] = 0;
64
65 this->VertexColor[0] = 0.5;
66 this->VertexColor[1] = 1.0;
67 this->VertexColor[2] = 0.5;
68
69 this->EmissiveFactor[0] = 1.0;
70 this->EmissiveFactor[1] = 1.0;
71 this->EmissiveFactor[2] = 1.0;
72
73 this->EdgeTint[0] = 1.0;
74 this->EdgeTint[1] = 1.0;
75 this->EdgeTint[2] = 1.0;
76
77 this->CoatColor[0] = 1.0;
78 this->CoatColor[1] = 1.0;
79 this->CoatColor[2] = 1.0;
80
81 this->NormalScale = 1.0;
82 this->OcclusionStrength = 1.0;
83 this->Metallic = 0.0;
84 this->BaseIOR = 1.5;
85 this->Roughness = 0.5;
86 this->Anisotropy = 0.0;
87 this->AnisotropyRotation = 0.0;
88 this->CoatIOR = 2.0;
89 this->CoatRoughness = 0.0;
90 this->CoatStrength = 0.0;
91 this->CoatNormalScale = 1.0;
92 this->Ambient = 0.0;
93 this->Diffuse = 1.0;
94 this->Specular = 0.0;
95 this->SpecularPower = 1.0;
96 this->Opacity = 1.0;
97 this->Interpolation = VTK_GOURAUD;
98 this->Representation = VTK_SURFACE;
99 this->EdgeVisibility = 0;
100 this->VertexVisibility = 0;
101 this->BackfaceCulling = 0;
102 this->FrontfaceCulling = 0;
103 this->PointSize = 1.0;
104 this->LineWidth = 1.0;
105 this->LineStipplePattern = 0xFFFF;
106 this->LineStippleRepeatFactor = 1;
107 this->Lighting = true;
108 this->RenderPointsAsSpheres = false;
109 this->RenderLinesAsTubes = false;
110 this->ShowTexturesOnBackface = true;
111
112 this->Shading = 0;
113 this->MaterialName = nullptr;
114
115 this->Information = vtkInformation::New();
116 this->Information->Register(this);
117 this->Information->Delete();
118 }
119
120 //------------------------------------------------------------------------------
~vtkProperty()121 vtkProperty::~vtkProperty()
122 {
123 this->RemoveAllTextures();
124 this->SetMaterialName(nullptr);
125
126 this->SetInformation(nullptr);
127 }
128
129 //------------------------------------------------------------------------------
130 // Assign one property to another.
DeepCopy(vtkProperty * p)131 void vtkProperty::DeepCopy(vtkProperty* p)
132 {
133 if (p != nullptr)
134 {
135 this->SetColor(p->GetColor());
136 this->SetAmbientColor(p->GetAmbientColor());
137 this->SetDiffuseColor(p->GetDiffuseColor());
138 this->SetSpecularColor(p->GetSpecularColor());
139 this->SetEdgeColor(p->GetEdgeColor());
140 this->SetVertexColor(p->GetVertexColor());
141 this->SetAmbient(p->GetAmbient());
142 this->SetDiffuse(p->GetDiffuse());
143 this->SetSpecular(p->GetSpecular());
144 this->SetSpecularPower(p->GetSpecularPower());
145 this->SetOpacity(p->GetOpacity());
146 this->SetInterpolation(p->GetInterpolation());
147 this->SetRepresentation(p->GetRepresentation());
148 this->SetEdgeVisibility(p->GetEdgeVisibility());
149 this->SetVertexVisibility(p->GetVertexVisibility());
150 this->SetBackfaceCulling(p->GetBackfaceCulling());
151 this->SetFrontfaceCulling(p->GetFrontfaceCulling());
152 this->SetPointSize(p->GetPointSize());
153 this->SetLineWidth(p->GetLineWidth());
154 this->SetLineStipplePattern(p->GetLineStipplePattern());
155 this->SetLineStippleRepeatFactor(p->GetLineStippleRepeatFactor());
156 this->SetLighting(p->GetLighting());
157 this->SetRenderPointsAsSpheres(p->GetRenderPointsAsSpheres());
158 this->SetRenderLinesAsTubes(p->GetRenderLinesAsTubes());
159 this->SetShading(p->GetShading());
160 this->SetNormalScale(p->GetNormalScale());
161 this->SetOcclusionStrength(p->GetOcclusionStrength());
162 this->SetMetallic(p->GetMetallic());
163 this->SetRoughness(p->GetRoughness());
164 this->SetAnisotropy(p->GetAnisotropy());
165 this->SetAnisotropyRotation(p->GetAnisotropyRotation());
166 this->SetBaseIOR(p->GetBaseIOR());
167 this->SetRoughness(p->GetRoughness());
168 this->SetCoatIOR(p->GetCoatIOR());
169 this->SetCoatRoughness(p->GetCoatRoughness());
170 this->SetCoatStrength(p->GetCoatStrength());
171 this->SetCoatNormalScale(p->GetCoatNormalScale());
172 this->SetCoatColor(p->GetCoatColor());
173 this->SetShowTexturesOnBackface(p->GetShowTexturesOnBackface());
174
175 this->RemoveAllTextures();
176 auto iter = p->Textures.begin();
177 for (; iter != p->Textures.end(); ++iter)
178 {
179 this->Textures[iter->first] = iter->second;
180 }
181 // TODO: need to pass shader variables.
182 }
183 }
184
185 //------------------------------------------------------------------------------
SetColor(double r,double g,double b)186 void vtkProperty::SetColor(double r, double g, double b)
187 {
188 double newColor[3] = { r, g, b };
189
190 // SetColor is shorthand for "set all colors"
191 double* color[4] = { this->Color, this->AmbientColor, this->DiffuseColor, this->SpecularColor };
192
193 // Set colors, and check for changes
194 bool modified = false;
195 for (int i = 0; i < 4; i++)
196 {
197 for (int j = 0; j < 3; j++)
198 {
199 if (color[i][j] != newColor[j])
200 {
201 modified = true;
202 color[i][j] = newColor[j];
203 }
204 }
205 }
206
207 // Call Modified() if anything changed
208 if (modified)
209 {
210 this->Modified();
211 }
212 }
213
214 //------------------------------------------------------------------------------
SetColor(double a[3])215 void vtkProperty::SetColor(double a[3])
216 {
217 this->SetColor(a[0], a[1], a[2]);
218 }
219
220 //------------------------------------------------------------------------------
ComputeCompositeColor(double result[3],double ambient,const double ambient_color[3],double diffuse,const double diffuse_color[3],double specular,const double specular_color[3])221 void vtkProperty::ComputeCompositeColor(double result[3], double ambient,
222 const double ambient_color[3], double diffuse, const double diffuse_color[3], double specular,
223 const double specular_color[3])
224 {
225 double norm = 0.0;
226 if ((ambient + diffuse + specular) > 0)
227 {
228 norm = 1.0 / (ambient + diffuse + specular);
229 }
230
231 for (int i = 0; i < 3; i++)
232 {
233 result[i] =
234 (ambient * ambient_color[i] + diffuse * diffuse_color[i] + specular * specular_color[i]) *
235 norm;
236 }
237 }
238
239 //------------------------------------------------------------------------------
ComputeReflectanceFromIOR(double IORTo,double IORFrom)240 double vtkProperty::ComputeReflectanceFromIOR(double IORTo, double IORFrom)
241 {
242 return std::pow(IORTo - IORFrom, 2) / std::pow(IORTo + IORFrom, 2);
243 }
244
245 //------------------------------------------------------------------------------
ComputeIORFromReflectance(double reflectance,double ior)246 double vtkProperty::ComputeIORFromReflectance(double reflectance, double ior)
247 {
248 return -ior * (std::sqrt(reflectance) + 1) / (std::sqrt(reflectance) - 1);
249 }
250
251 //------------------------------------------------------------------------------
ComputeReflectanceOfBaseLayer()252 double vtkProperty::ComputeReflectanceOfBaseLayer()
253 {
254 // Compute F0 of base with the environment
255 // Hard coded air environment (could be modified with an other IOR)
256 const double environmentIOR = 1.0;
257 double baseToEnvironmentF0 =
258 vtkProperty::ComputeReflectanceFromIOR(this->BaseIOR, environmentIOR);
259 // Recalculate base f0 in case of a coat layer
260 double baseToCoatF0 = vtkProperty::ComputeReflectanceFromIOR(this->BaseIOR, this->CoatIOR);
261 // Mix F0 depending on the coat strength
262 return baseToEnvironmentF0 * (1.0 - this->CoatStrength) + baseToCoatF0 * this->CoatStrength;
263 }
264
265 //------------------------------------------------------------------------------
266 // Return composite color of object (ambient + diffuse + specular). Return value
267 // is a pointer to rgb values.
GetColor()268 double* vtkProperty::GetColor()
269 {
270 vtkProperty::ComputeCompositeColor(this->Color, this->Ambient, this->AmbientColor, this->Diffuse,
271 this->DiffuseColor, this->Specular, this->SpecularColor);
272 return this->Color;
273 }
274
275 //------------------------------------------------------------------------------
276 // Copy composite color of object (ambient + diffuse + specular) into array
277 // provided.
GetColor(double rgb[3])278 void vtkProperty::GetColor(double rgb[3])
279 {
280 this->GetColor();
281 rgb[0] = this->Color[0];
282 rgb[1] = this->Color[1];
283 rgb[2] = this->Color[2];
284 }
285
286 //------------------------------------------------------------------------------
GetColor(double & r,double & g,double & b)287 void vtkProperty::GetColor(double& r, double& g, double& b)
288 {
289 this->GetColor();
290 r = this->Color[0];
291 g = this->Color[1];
292 b = this->Color[2];
293 }
294
295 //------------------------------------------------------------------------------
SetTexture(const char * name,vtkTexture * tex)296 void vtkProperty::SetTexture(const char* name, vtkTexture* tex)
297 {
298 if (tex == nullptr)
299 {
300 this->RemoveTexture(name);
301 return;
302 }
303
304 if ((strcmp(name, "albedoTex") == 0 || strcmp(name, "emissiveTex") == 0) &&
305 !tex->GetUseSRGBColorSpace())
306 {
307 vtkErrorMacro("The " << name << " texture is not in sRGB color space.");
308 return;
309 }
310 const bool texNeedLinear = strcmp(name, "materialTex") == 0 || strcmp(name, "normalTex") == 0 ||
311 strcmp(name, "anisotropyTex") == 0 || strcmp(name, "coatNormalTex") == 0;
312 if (texNeedLinear && tex->GetUseSRGBColorSpace())
313 {
314 vtkErrorMacro("The " << name << " texture is not in linear color space.");
315 return;
316 }
317
318 auto iter = this->Textures.find(std::string(name));
319 if (iter != this->Textures.end())
320 {
321 // same value?
322 if (iter->second == tex)
323 {
324 return;
325 }
326 vtkWarningMacro("Texture with name " << name << " exists. It will be replaced.");
327 iter->second->UnRegister(this);
328 }
329
330 tex->Register(this);
331 this->Textures[name] = tex;
332 this->Modified();
333 }
334
335 //------------------------------------------------------------------------------
GetTexture(const char * name)336 vtkTexture* vtkProperty::GetTexture(const char* name)
337 {
338 auto iter = this->Textures.find(std::string(name));
339 if (iter == this->Textures.end())
340 {
341 return nullptr;
342 }
343
344 return iter->second;
345 }
346
347 //------------------------------------------------------------------------------
GetNumberOfTextures()348 int vtkProperty::GetNumberOfTextures()
349 {
350 return static_cast<int>(this->Textures.size());
351 }
352
353 //------------------------------------------------------------------------------
RemoveTexture(const char * name)354 void vtkProperty::RemoveTexture(const char* name)
355 {
356 auto iter = this->Textures.find(std::string(name));
357 if (iter != this->Textures.end())
358 {
359 iter->second->UnRegister(this);
360 this->Textures.erase(iter);
361 this->Modified();
362 }
363 }
364
365 //------------------------------------------------------------------------------
RemoveAllTextures()366 void vtkProperty::RemoveAllTextures()
367 {
368 while (!this->Textures.empty())
369 {
370 auto iter = this->Textures.begin();
371 iter->second->UnRegister(this);
372 this->Textures.erase(iter);
373 }
374 this->Modified();
375 }
376
377 //------------------------------------------------------------------------------
Render(vtkActor *,vtkRenderer * renderer)378 void vtkProperty::Render(vtkActor*, vtkRenderer* renderer)
379 {
380 // subclass would have renderer the property already.
381 // this class, just handles the shading.
382
383 if (renderer->GetSelector())
384 {
385 // nothing to do when rendering for hardware selection.
386 return;
387 }
388 }
389
390 //------------------------------------------------------------------------------
PostRender(vtkActor *,vtkRenderer * renderer)391 void vtkProperty::PostRender(vtkActor*, vtkRenderer* renderer)
392 {
393 if (renderer->GetSelector())
394 {
395 // nothing to do when rendering for hardware selection.
396 return;
397 }
398 }
399
400 //------------------------------------------------------------------------------
AddShaderVariable(const char *,int,int *)401 void vtkProperty::AddShaderVariable(const char*, int, int*) {}
402
403 //------------------------------------------------------------------------------
AddShaderVariable(const char *,int,float *)404 void vtkProperty::AddShaderVariable(const char*, int, float*) {}
405
406 //------------------------------------------------------------------------------
AddShaderVariable(const char *,int,double *)407 void vtkProperty::AddShaderVariable(const char*, int, double*) {}
408
409 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow *)410 void vtkProperty::ReleaseGraphicsResources(vtkWindow*)
411 {
412 // vtkOpenGLRenderer releases texture resources, so we don't need to release
413 // them here.
414 }
415
416 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)417 void vtkProperty::PrintSelf(ostream& os, vtkIndent indent)
418 {
419 this->Superclass::PrintSelf(os, indent);
420
421 os << indent << "Ambient: " << this->Ambient << "\n";
422 os << indent << "Ambient Color: (" << this->AmbientColor[0] << ", " << this->AmbientColor[1]
423 << ", " << this->AmbientColor[2] << ")\n";
424 os << indent << "Diffuse: " << this->Diffuse << "\n";
425 os << indent << "Diffuse Color: (" << this->DiffuseColor[0] << ", " << this->DiffuseColor[1]
426 << ", " << this->DiffuseColor[2] << ")\n";
427 os << indent << "Edge Color: (" << this->EdgeColor[0] << ", " << this->EdgeColor[1] << ", "
428 << this->EdgeColor[2] << ")\n";
429 os << indent << "Edge Visibility: " << (this->EdgeVisibility ? "On\n" : "Off\n");
430 os << indent << "Vertex Color: (" << this->VertexColor[0] << ", " << this->VertexColor[1] << ", "
431 << this->VertexColor[2] << ")\n";
432 os << indent << "Vertex Visibility: " << (this->VertexVisibility ? "On\n" : "Off\n");
433 os << indent << "Interpolation: ";
434 switch (this->Interpolation)
435 {
436 case VTK_FLAT:
437 os << "VTK_FLAT\n";
438 break;
439 case VTK_GOURAUD:
440 os << "VTK_GOURAUD\n";
441 break;
442 case VTK_PHONG:
443 os << "VTK_PHONG\n";
444 break;
445 case VTK_PBR:
446 os << "VTK_PBR\n";
447 break;
448 default:
449 os << "unknown\n";
450 }
451 os << indent << "Opacity: " << this->Opacity << "\n";
452 os << indent << "Representation: ";
453 switch (this->Representation)
454 {
455 case VTK_POINTS:
456 os << "VTK_POINTS\n";
457 break;
458 case VTK_WIREFRAME:
459 os << "VTK_WIREFRAME\n";
460 break;
461 case VTK_SURFACE:
462 os << "VTK_SURFACE\n";
463 break;
464 default:
465 os << "unknown\n";
466 }
467 os << indent << "Specular: " << this->Specular << "\n";
468 os << indent << "Specular Color: (" << this->SpecularColor[0] << ", " << this->SpecularColor[1]
469 << ", " << this->SpecularColor[2] << ")\n";
470 os << indent << "Specular Power: " << this->SpecularPower << "\n";
471 os << indent << "Backface Culling: " << (this->BackfaceCulling ? "On\n" : "Off\n");
472 os << indent << "Frontface Culling: " << (this->FrontfaceCulling ? "On\n" : "Off\n");
473 os << indent << "Point size: " << this->PointSize << "\n";
474 os << indent << "Line width: " << this->LineWidth << "\n";
475 os << indent << "Line stipple pattern: " << this->LineStipplePattern << "\n";
476 os << indent << "Line stipple repeat factor: " << this->LineStippleRepeatFactor << "\n";
477 os << indent << "Lighting: ";
478 if (this->Lighting)
479 {
480 os << "On" << endl;
481 }
482 else
483 {
484 os << "Off" << endl;
485 }
486 os << indent << "RenderPointsAsSpheres: " << (this->RenderPointsAsSpheres ? "On" : "Off") << endl;
487 os << indent << "RenderLinesAsTubes: " << (this->RenderLinesAsTubes ? "On" : "Off") << endl;
488 os << indent << "ShowTexturesOnBackface: " << (this->ShowTexturesOnBackface ? "On" : "Off")
489 << endl;
490
491 os << indent << "Shading: " << (this->Shading ? "On" : "Off") << endl;
492
493 os << indent << "MaterialName: " << (this->MaterialName ? this->MaterialName : "(none)") << endl;
494
495 os << indent << "Color: (" << this->Color[0] << ", " << this->Color[1] << ", " << this->Color[2]
496 << ")" << endl;
497 os << indent << "EmissiveFactor: (" << this->EmissiveFactor[0] << ", " << this->EmissiveFactor[1]
498 << ", " << this->EmissiveFactor[2] << ")" << endl;
499 os << indent << "NormalScale: " << this->NormalScale << endl;
500 os << indent << "OcclusionStrength: " << this->OcclusionStrength << endl;
501 os << indent << "Metallic: " << this->Metallic << endl;
502 os << indent << "Roughness: " << this->Roughness << endl;
503 }
504