0032530: Data Exchange, RWGltf_CafWriter - add option merging Faces within the Part
[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   myFaceCulling (Graphic3d_TypeOfBackfacingModel_Auto)
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 : SetFaceCulling
80 //purpose  :
81 //=======================================================================
82 void XCAFDoc_VisMaterial::SetFaceCulling (Graphic3d_TypeOfBackfacingModel theFaceCulling)
83 {
84   Backup();
85   myFaceCulling = theFaceCulling;
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   myFaceCulling   = anOther->myFaceCulling;
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->myFaceCulling   = myFaceCulling;
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.DiffuseTexture = myPbrMat.BaseColorTexture;
163   aComMat.DiffuseColor  = myPbrMat.BaseColor.GetRGB();
164   aComMat.SpecularColor = Quantity_Color (Graphic3d_Vec3 (myPbrMat.Metallic));
165   aComMat.Transparency = 1.0f - myPbrMat.BaseColor.Alpha();
166   aComMat.Shininess    = 1.0f - myPbrMat.Roughness;
167   if (myPbrMat.EmissiveTexture.IsNull())
168   {
169     aComMat.EmissiveColor = Quantity_Color (myPbrMat.EmissiveFactor.cwiseMin (Graphic3d_Vec3 (1.0f)));
170   }
171   return aComMat;
172 }
173
174 //=======================================================================
175 //function : ConvertToPbrMaterial
176 //purpose  :
177 //=======================================================================
178 XCAFDoc_VisMaterialPBR XCAFDoc_VisMaterial::ConvertToPbrMaterial()
179 {
180   if (myPbrMat.IsDefined)
181   {
182     return myPbrMat;
183   }
184   else if (!myCommonMat.IsDefined)
185   {
186     return XCAFDoc_VisMaterialPBR();
187   }
188
189   XCAFDoc_VisMaterialPBR aPbrMat;
190   aPbrMat.IsDefined = true;
191   aPbrMat.BaseColorTexture = myCommonMat.DiffuseTexture;
192   aPbrMat.BaseColor.SetRGB (myCommonMat.DiffuseColor);
193   aPbrMat.BaseColor.SetAlpha (1.0f - myCommonMat.Transparency);
194   aPbrMat.Metallic  = myCommonMat.Transparency <= ShortRealEpsilon()
195                     ? Graphic3d_PBRMaterial::MetallicFromSpecular (myCommonMat.SpecularColor)
196                     : 0.0f;
197   aPbrMat.Roughness = Graphic3d_PBRMaterial::RoughnessFromSpecular (myCommonMat.SpecularColor, myCommonMat.Shininess);
198   aPbrMat.EmissiveFactor = myCommonMat.EmissiveColor;
199   return aPbrMat;
200 }
201
202 //=======================================================================
203 //function : FillMaterialAspect
204 //purpose  :
205 //=======================================================================
206 void XCAFDoc_VisMaterial::FillMaterialAspect (Graphic3d_MaterialAspect& theAspect) const
207 {
208   if (myCommonMat.IsDefined)
209   {
210     theAspect = Graphic3d_MaterialAspect (Graphic3d_NameOfMaterial_UserDefined);
211     theAspect.SetAmbientColor (myCommonMat.AmbientColor);
212     theAspect.SetDiffuseColor (myCommonMat.DiffuseColor);
213     theAspect.SetSpecularColor(myCommonMat.SpecularColor);
214     theAspect.SetEmissiveColor(myCommonMat.EmissiveColor);
215     theAspect.SetTransparency (myCommonMat.Transparency);
216     theAspect.SetShininess    (myCommonMat.Shininess);
217
218     // convert common into metal-roughness
219     if (!myPbrMat.IsDefined)
220     {
221       Graphic3d_PBRMaterial aPbr;
222       aPbr.SetColor (myCommonMat.DiffuseColor);
223       aPbr.SetMetallic (myCommonMat.Transparency <= ShortRealEpsilon()
224                       ? Graphic3d_PBRMaterial::MetallicFromSpecular (myCommonMat.SpecularColor)
225                       : 0.0f);
226       aPbr.SetRoughness (Graphic3d_PBRMaterial::RoughnessFromSpecular (myCommonMat.SpecularColor, myCommonMat.Shininess));
227       aPbr.SetEmission (myCommonMat.EmissiveColor);
228       theAspect.SetPBRMaterial (aPbr);
229       theAspect.SetBSDF (Graphic3d_BSDF::CreateMetallicRoughness (aPbr));
230     }
231   }
232
233   if (myPbrMat.IsDefined)
234   {
235     if (!myCommonMat.IsDefined)
236     {
237       // convert metal-roughness into common
238       theAspect = Graphic3d_MaterialAspect (Graphic3d_NameOfMaterial_UserDefined);
239       theAspect.SetDiffuseColor (myPbrMat.BaseColor.GetRGB());
240       theAspect.SetAlpha        (myPbrMat.BaseColor.Alpha());
241       theAspect.SetSpecularColor(Quantity_Color (Graphic3d_Vec3 (myPbrMat.Metallic)));
242       theAspect.SetShininess    (1.0f - myPbrMat.Roughness);
243       if (theAspect.Shininess() < 0.01f)
244       {
245         // clamp too small shininess values causing visual artifacts on corner view angles
246         theAspect.SetShininess (0.01f);
247       }
248       theAspect.SetEmissiveColor (Quantity_Color (myPbrMat.EmissiveFactor.cwiseMin (Graphic3d_Vec3 (1.0f))));
249     }
250
251     Graphic3d_PBRMaterial aPbr;
252     aPbr.SetColor    (myPbrMat.BaseColor);
253     aPbr.SetMetallic (myPbrMat.Metallic);
254     aPbr.SetRoughness(myPbrMat.Roughness);
255     aPbr.SetEmission (myPbrMat.EmissiveFactor);
256     aPbr.SetIOR      (myPbrMat.RefractionIndex);
257     theAspect.SetRefractionIndex (myPbrMat.RefractionIndex);
258     theAspect.SetPBRMaterial (aPbr);
259     theAspect.SetBSDF (Graphic3d_BSDF::CreateMetallicRoughness (aPbr));
260   }
261 }
262
263 //=======================================================================
264 //function : FillAspect
265 //purpose  :
266 //=======================================================================
267 void XCAFDoc_VisMaterial::FillAspect (const Handle(Graphic3d_Aspects)& theAspect) const
268 {
269   if (IsEmpty())
270   {
271     return;
272   }
273
274   Graphic3d_MaterialAspect aMaterial;
275   FillMaterialAspect (aMaterial);
276   theAspect->SetFrontMaterial (aMaterial);
277   theAspect->SetAlphaMode (myAlphaMode , myAlphaCutOff);
278   theAspect->SetFaceCulling (myFaceCulling);
279
280   const Handle(Image_Texture)& aColorTexture = !myPbrMat.BaseColorTexture.IsNull() ? myPbrMat.BaseColorTexture : myCommonMat.DiffuseTexture;
281   Standard_Integer aNbTexUnits = 0;
282   if (!aColorTexture.IsNull())             { ++aNbTexUnits; }
283   if (!myPbrMat.EmissiveTexture.IsNull())  { ++aNbTexUnits; }
284   if (!myPbrMat.NormalTexture.IsNull())    { ++aNbTexUnits; }
285   if (!myPbrMat.OcclusionTexture.IsNull()) { ++aNbTexUnits; }
286   if (!myPbrMat.MetallicRoughnessTexture.IsNull()) { ++aNbTexUnits; }
287   if (aNbTexUnits == 0)
288   {
289     return;
290   }
291
292   Standard_Integer aTexIter = 0;
293   Handle(Graphic3d_TextureSet) aTextureSet = new Graphic3d_TextureSet (aNbTexUnits);
294   if (!aColorTexture.IsNull())
295   {
296     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*aColorTexture, Graphic3d_TextureUnit_BaseColor));
297   }
298   if (!myPbrMat.EmissiveTexture.IsNull())
299   {
300     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.EmissiveTexture, Graphic3d_TextureUnit_Emissive));
301   }
302   if (!myPbrMat.OcclusionTexture.IsNull())
303   {
304     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.OcclusionTexture, Graphic3d_TextureUnit_Occlusion));
305   }
306   if (!myPbrMat.NormalTexture.IsNull())
307   {
308     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.NormalTexture, Graphic3d_TextureUnit_Normal));
309   }
310   if (!myPbrMat.MetallicRoughnessTexture.IsNull())
311   {
312     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.MetallicRoughnessTexture, Graphic3d_TextureUnit_MetallicRoughness));
313   }
314
315   theAspect->SetTextureSet (aTextureSet);
316   theAspect->SetTextureMapOn (true);
317 }
318
319 //=======================================================================
320 //function : DumpJson
321 //purpose  : 
322 //=======================================================================
323 void XCAFDoc_VisMaterial::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
324 {
325   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
326
327   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, TDF_Attribute)
328
329   OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myRawName.get())
330
331   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myPbrMat)
332   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myCommonMat)
333
334   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAlphaMode)
335   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAlphaCutOff)
336   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myFaceCulling)
337 }