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