0029902: Data Exchange, XCAF - provide extended Material definition for visualization...
[occt.git] / src / XCAFDoc / XCAFDoc_VisMaterial.cxx
1 // Copyright (c) 2019 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <XCAFDoc_VisMaterial.hxx>
15
16 #include <Graphic3d_Aspects.hxx>
17 #include <Graphic3d_MaterialAspect.hxx>
18 #include <Standard_GUID.hxx>
19 #include <TDF_Label.hxx>
20 #include <XCAFPrs_Texture.hxx>
21
22 IMPLEMENT_STANDARD_RTTIEXT(XCAFDoc_VisMaterial, TDF_Attribute)
23
24 //=======================================================================
25 //function : GetID
26 //purpose  :
27 //=======================================================================
28 const Standard_GUID& XCAFDoc_VisMaterial::GetID()
29 {
30   static Standard_GUID THE_VIS_MAT_ID ("EBB00255-03A0-4845-BD3B-A70EEDEEFA78");
31   return THE_VIS_MAT_ID;
32 }
33
34 //=======================================================================
35 //function : Constructor
36 //purpose  :
37 //=======================================================================
38 XCAFDoc_VisMaterial::XCAFDoc_VisMaterial()
39 : myAlphaMode (Graphic3d_AlphaMode_BlendAuto),
40   myAlphaCutOff (0.5f),
41   myIsDoubleSided (Standard_True)
42 {
43   //
44 }
45
46 //=======================================================================
47 //function : SetMetalRougnessMaterial
48 //purpose  :
49 //=======================================================================
50 void XCAFDoc_VisMaterial::SetPbrMaterial (const XCAFDoc_VisMaterialPBR& theMaterial)
51 {
52   Backup();
53   myPbrMat = theMaterial;
54 }
55
56 //=======================================================================
57 //function : SetCommonMaterial
58 //purpose  :
59 //=======================================================================
60 void XCAFDoc_VisMaterial::SetCommonMaterial (const XCAFDoc_VisMaterialCommon& theMaterial)
61 {
62   Backup();
63   myCommonMat = theMaterial;
64 }
65
66 //=======================================================================
67 //function : SetAlphaMode
68 //purpose  :
69 //=======================================================================
70 void XCAFDoc_VisMaterial::SetAlphaMode (Graphic3d_AlphaMode theMode,
71                                         Standard_ShortReal  theCutOff)
72 {
73   Backup();
74   myAlphaMode   = theMode;
75   myAlphaCutOff = theCutOff;
76 }
77
78 //=======================================================================
79 //function : SetDoubleSided
80 //purpose  :
81 //=======================================================================
82 void XCAFDoc_VisMaterial::SetDoubleSided (Standard_Boolean theIsDoubleSided)
83 {
84   Backup();
85   myIsDoubleSided = theIsDoubleSided;
86 }
87
88 //=======================================================================
89 //function : Restore
90 //purpose  :
91 //=======================================================================
92 void XCAFDoc_VisMaterial::Restore (const Handle(TDF_Attribute)& theWith)
93 {
94   XCAFDoc_VisMaterial* anOther = dynamic_cast<XCAFDoc_VisMaterial* >(theWith.get());
95   myPbrMat        = anOther->myPbrMat;
96   myCommonMat     = anOther->myCommonMat;
97   myAlphaMode     = anOther->myAlphaMode;
98   myAlphaCutOff   = anOther->myAlphaCutOff;
99   myIsDoubleSided = anOther->myIsDoubleSided;
100 }
101
102 //=======================================================================
103 //function : NewEmpty
104 //purpose  :
105 //=======================================================================
106 Handle(TDF_Attribute) XCAFDoc_VisMaterial::NewEmpty() const
107 {
108   return new XCAFDoc_VisMaterial();
109 }
110
111 //=======================================================================
112 //function : Paste
113 //purpose  :
114 //=======================================================================
115 void XCAFDoc_VisMaterial::Paste (const Handle(TDF_Attribute)& theInto,
116                                  const Handle(TDF_RelocationTable)& ) const
117 {
118   XCAFDoc_VisMaterial* anOther = dynamic_cast<XCAFDoc_VisMaterial* >(theInto.get());
119   anOther->Backup();
120   anOther->myPbrMat        = myPbrMat;
121   anOther->myCommonMat     = myCommonMat;
122   anOther->myAlphaMode     = myAlphaMode;
123   anOther->myAlphaCutOff   = myAlphaCutOff;
124   anOther->myIsDoubleSided = myIsDoubleSided;
125 }
126
127 // =======================================================================
128 // function : BaseColor
129 // purpose  :
130 // =======================================================================
131 Quantity_ColorRGBA XCAFDoc_VisMaterial::BaseColor() const
132 {
133   if (myPbrMat.IsDefined)
134   {
135     return myPbrMat.BaseColor;
136   }
137   else if (myCommonMat.IsDefined)
138   {
139     return Quantity_ColorRGBA (myCommonMat.DiffuseColor, 1.0f - myCommonMat.Transparency);
140   }
141   return Quantity_ColorRGBA (Quantity_NOC_WHITE);
142 }
143
144 //=======================================================================
145 //function : ConvertToCommonMaterial
146 //purpose  :
147 //=======================================================================
148 XCAFDoc_VisMaterialCommon XCAFDoc_VisMaterial::ConvertToCommonMaterial()
149 {
150   if (myCommonMat.IsDefined)
151   {
152     return myCommonMat;
153   }
154   else if (!myPbrMat.IsDefined)
155   {
156     return XCAFDoc_VisMaterialCommon();
157   }
158
159   // convert metal-roughness into common
160   XCAFDoc_VisMaterialCommon aComMat;
161   aComMat.IsDefined = true;
162   aComMat.DiffuseColor  = myPbrMat.BaseColor.GetRGB();
163   aComMat.SpecularColor = Quantity_Color (Graphic3d_Vec3 (myPbrMat.Metallic));
164   aComMat.Transparency = 1.0f - myPbrMat.BaseColor.Alpha();
165   aComMat.Shininess    = 1.0f - myPbrMat.Roughness;
166   return aComMat;
167 }
168
169 //! Compute material roughness from common material.
170 static Standard_ShortReal roughnessFromCommon (const XCAFDoc_VisMaterialCommon& theMat)
171 {
172   Standard_Real aRoughnessFactor = 1.0 - theMat.Shininess;
173   //Standard_Real aSpecIntens = theMat.SpecularColor.Light() * theMat.SpecularColor;
174   const Standard_Real aSpecIntens = theMat.SpecularColor.Red()   * 0.2125
175                                   + theMat.SpecularColor.Green() * 0.7154
176                                   + theMat.SpecularColor.Blue()  * 0.0721;
177   if (aSpecIntens < 0.1)
178   {
179     // low specular intensity should produce a rough material even if shininess is high
180     aRoughnessFactor *= (1.0 - aSpecIntens);
181   }
182   return (Standard_ShortReal )aRoughnessFactor;
183 }
184
185 //=======================================================================
186 //function : ConvertToPbrMaterial
187 //purpose  :
188 //=======================================================================
189 XCAFDoc_VisMaterialPBR XCAFDoc_VisMaterial::ConvertToPbrMaterial()
190 {
191   if (myPbrMat.IsDefined)
192   {
193     return myPbrMat;
194   }
195   else if (!myCommonMat.IsDefined)
196   {
197     return XCAFDoc_VisMaterialPBR();
198   }
199
200   XCAFDoc_VisMaterialPBR aPbrMat;
201   aPbrMat.IsDefined = true;
202   aPbrMat.BaseColor.SetRGB (myCommonMat.DiffuseColor);
203   aPbrMat.BaseColor.SetAlpha (1.0f - myCommonMat.Transparency);
204   // we allow to save any number in range [0, 1] but logically metallicity can be either 0 or 1
205   aPbrMat.Metallic = ((Graphic3d_Vec3 )myCommonMat.SpecularColor).maxComp(); // > 0.1f ? 1.0 : 0.0;
206   aPbrMat.Roughness = roughnessFromCommon (myCommonMat);
207   return aPbrMat;
208 }
209
210 //=======================================================================
211 //function : FillMaterialAspect
212 //purpose  :
213 //=======================================================================
214 void XCAFDoc_VisMaterial::FillMaterialAspect (Graphic3d_MaterialAspect& theAspect) const
215 {
216   if (myCommonMat.IsDefined)
217   {
218     theAspect = Graphic3d_MaterialAspect (Graphic3d_NOM_UserDefined);
219     theAspect.SetAmbientColor (myCommonMat.AmbientColor);
220     theAspect.SetDiffuseColor (myCommonMat.DiffuseColor);
221     theAspect.SetSpecularColor(myCommonMat.SpecularColor);
222     theAspect.SetEmissiveColor(myCommonMat.EmissiveColor);
223     theAspect.SetTransparency (myCommonMat.Transparency);
224     theAspect.SetShininess    (myCommonMat.Shininess);
225
226     // convert common into metal-roughness
227     if (!myPbrMat.IsDefined)
228     {
229     #ifdef _Graphic3d_PBRMaterial_HeaderFile
230       Graphic3d_PBRMaterial aPbr;
231       aPbr.SetColor (myCommonMat.DiffuseColor);
232       aPbr.SetMetallic (((Graphic3d_Vec3 )myCommonMat.SpecularColor).maxComp());
233       aPbr.SetRoughness (roughnessFromCommon (myCommonMat));
234       theAspect.SetPBRMaterial (aPbr);
235     #endif
236     }
237   }
238
239   if (myPbrMat.IsDefined)
240   {
241     if (!myCommonMat.IsDefined)
242     {
243       // convert metal-roughness into common
244       theAspect = Graphic3d_MaterialAspect (Graphic3d_NOM_UserDefined);
245       theAspect.SetDiffuseColor (myPbrMat.BaseColor.GetRGB());
246       theAspect.SetAlpha        (myPbrMat.BaseColor.Alpha());
247       theAspect.SetSpecularColor(Quantity_Color (Graphic3d_Vec3 (myPbrMat.Metallic)));
248       theAspect.SetShininess    (1.0f - myPbrMat.Roughness);
249     }
250
251   #ifdef _Graphic3d_PBRMaterial_HeaderFile
252     Graphic3d_PBRMaterial aPbr;
253     aPbr.SetColor    (myPbrMat.BaseColor);
254     aPbr.SetMetallic (myPbrMat.Metallic);
255     aPbr.SetRoughness(myPbrMat.Roughness);
256     aPbr.SetEmission (myPbrMat.EmissiveFactor);
257     theAspect.SetPBRMaterial (aPbr);
258   #endif
259   }
260 }
261
262 //=======================================================================
263 //function : FillAspect
264 //purpose  :
265 //=======================================================================
266 void XCAFDoc_VisMaterial::FillAspect (const Handle(Graphic3d_Aspects)& theAspect) const
267 {
268   if (IsEmpty())
269   {
270     return;
271   }
272
273   Graphic3d_MaterialAspect aMaterial;
274   FillMaterialAspect (aMaterial);
275   theAspect->SetFrontMaterial (aMaterial);
276   theAspect->SetAlphaMode (myAlphaMode , myAlphaCutOff);
277   theAspect->SetSuppressBackFaces (!myIsDoubleSided);
278
279   Handle(Image_Texture) aColorTexture, aNormTexture;
280   if (!myCommonMat.DiffuseTexture.IsNull())
281   {
282     aColorTexture = myCommonMat.DiffuseTexture;
283   }
284   else if (!myPbrMat.BaseColorTexture.IsNull())
285   {
286     aColorTexture = myPbrMat.BaseColorTexture;
287   }
288
289   if (!myPbrMat.NormalTexture.IsNull())
290   {
291     aNormTexture = myPbrMat.NormalTexture;
292   }
293
294   Standard_Integer aNbTextures = 0;
295   if (!aColorTexture.IsNull())
296   {
297     ++aNbTextures;
298   }
299   if (!aNormTexture.IsNull())
300   {
301     //++aNbTextures;
302   }
303   if (aNbTextures != 0)
304   {
305     Handle(Graphic3d_TextureSet) aTextureSet = new Graphic3d_TextureSet (aNbTextures);
306     Standard_Integer aTextureIndex = 0;
307     if (!aColorTexture.IsNull())
308     {
309       aTextureSet->SetValue (aTextureIndex++, new XCAFPrs_Texture (*aColorTexture, Graphic3d_TextureUnit_BaseColor));
310     }
311     if (!aNormTexture.IsNull())
312     {
313       //aTextureSet->SetValue (aTextureIndex++, new XCAFPrs_Texture (*aColorTexture, Graphic3d_TextureUnit_Normal));
314     }
315     theAspect->SetTextureSet (aTextureSet);
316     theAspect->SetTextureMapOn (true);
317   }
318 }