0031096: Visualization, TKOpenGl - support metallic-roughness texture mapping
[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.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   return aComMat;
168 }
169
170 //=======================================================================
171 //function : ConvertToPbrMaterial
172 //purpose  :
173 //=======================================================================
174 XCAFDoc_VisMaterialPBR XCAFDoc_VisMaterial::ConvertToPbrMaterial()
175 {
176   if (myPbrMat.IsDefined)
177   {
178     return myPbrMat;
179   }
180   else if (!myCommonMat.IsDefined)
181   {
182     return XCAFDoc_VisMaterialPBR();
183   }
184
185   XCAFDoc_VisMaterialPBR aPbrMat;
186   aPbrMat.IsDefined = true;
187   aPbrMat.BaseColorTexture = myCommonMat.DiffuseTexture;
188   aPbrMat.BaseColor.SetRGB (myCommonMat.DiffuseColor);
189   aPbrMat.BaseColor.SetAlpha (1.0f - myCommonMat.Transparency);
190   aPbrMat.Metallic  = Graphic3d_PBRMaterial::MetallicFromSpecular (myCommonMat.SpecularColor);
191   aPbrMat.Roughness = Graphic3d_PBRMaterial::RoughnessFromSpecular (myCommonMat.SpecularColor, myCommonMat.Shininess);
192   return aPbrMat;
193 }
194
195 //=======================================================================
196 //function : FillMaterialAspect
197 //purpose  :
198 //=======================================================================
199 void XCAFDoc_VisMaterial::FillMaterialAspect (Graphic3d_MaterialAspect& theAspect) const
200 {
201   if (myCommonMat.IsDefined)
202   {
203     theAspect = Graphic3d_MaterialAspect (Graphic3d_NOM_UserDefined);
204     theAspect.SetAmbientColor (myCommonMat.AmbientColor);
205     theAspect.SetDiffuseColor (myCommonMat.DiffuseColor);
206     theAspect.SetSpecularColor(myCommonMat.SpecularColor);
207     theAspect.SetEmissiveColor(myCommonMat.EmissiveColor);
208     theAspect.SetTransparency (myCommonMat.Transparency);
209     theAspect.SetShininess    (myCommonMat.Shininess);
210
211     // convert common into metal-roughness
212     if (!myPbrMat.IsDefined)
213     {
214       Graphic3d_PBRMaterial aPbr;
215       aPbr.SetColor (myCommonMat.DiffuseColor);
216       aPbr.SetMetallic (Graphic3d_PBRMaterial::MetallicFromSpecular (myCommonMat.SpecularColor));
217       aPbr.SetRoughness (Graphic3d_PBRMaterial::RoughnessFromSpecular (myCommonMat.SpecularColor, myCommonMat.Shininess));
218       theAspect.SetPBRMaterial (aPbr);
219       theAspect.SetBSDF (Graphic3d_BSDF::CreateMetallicRoughness (aPbr));
220     }
221   }
222
223   if (myPbrMat.IsDefined)
224   {
225     if (!myCommonMat.IsDefined)
226     {
227       // convert metal-roughness into common
228       theAspect = Graphic3d_MaterialAspect (Graphic3d_NOM_UserDefined);
229       theAspect.SetDiffuseColor (myPbrMat.BaseColor.GetRGB());
230       theAspect.SetAlpha        (myPbrMat.BaseColor.Alpha());
231       theAspect.SetSpecularColor(Quantity_Color (Graphic3d_Vec3 (myPbrMat.Metallic)));
232       theAspect.SetShininess    (1.0f - myPbrMat.Roughness);
233     }
234
235     Graphic3d_PBRMaterial aPbr;
236     aPbr.SetColor    (myPbrMat.BaseColor);
237     aPbr.SetMetallic (myPbrMat.Metallic);
238     aPbr.SetRoughness(myPbrMat.Roughness);
239     aPbr.SetEmission (myPbrMat.EmissiveFactor);
240     theAspect.SetPBRMaterial (aPbr);
241     theAspect.SetBSDF (Graphic3d_BSDF::CreateMetallicRoughness (aPbr));
242   }
243 }
244
245 //=======================================================================
246 //function : FillAspect
247 //purpose  :
248 //=======================================================================
249 void XCAFDoc_VisMaterial::FillAspect (const Handle(Graphic3d_Aspects)& theAspect) const
250 {
251   if (IsEmpty())
252   {
253     return;
254   }
255
256   Graphic3d_MaterialAspect aMaterial;
257   FillMaterialAspect (aMaterial);
258   theAspect->SetFrontMaterial (aMaterial);
259   theAspect->SetAlphaMode (myAlphaMode , myAlphaCutOff);
260   theAspect->SetSuppressBackFaces (!myIsDoubleSided);
261
262   const Handle(Image_Texture)& aColorTexture = !myPbrMat.BaseColorTexture.IsNull() ? myPbrMat.BaseColorTexture : myCommonMat.DiffuseTexture;
263   Standard_Integer aNbTexUnits = 0;
264   if (!aColorTexture.IsNull())             { ++aNbTexUnits; }
265   if (!myPbrMat.EmissiveTexture.IsNull())  { ++aNbTexUnits; }
266   if (!myPbrMat.NormalTexture.IsNull())    { ++aNbTexUnits; }
267   if (!myPbrMat.OcclusionTexture.IsNull()) { ++aNbTexUnits; }
268   if (!myPbrMat.MetallicRoughnessTexture.IsNull()) { ++aNbTexUnits; }
269   if (aNbTexUnits == 0)
270   {
271     return;
272   }
273
274   Standard_Integer aTexIter = 0;
275   Handle(Graphic3d_TextureSet) aTextureSet = new Graphic3d_TextureSet (aNbTexUnits);
276   if (!aColorTexture.IsNull())
277   {
278     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*aColorTexture, Graphic3d_TextureUnit_BaseColor));
279   }
280   if (!myPbrMat.EmissiveTexture.IsNull())
281   {
282     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.EmissiveTexture, Graphic3d_TextureUnit_Emissive));
283   }
284   if (!myPbrMat.OcclusionTexture.IsNull())
285   {
286     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.OcclusionTexture, Graphic3d_TextureUnit_Occlusion));
287   }
288   if (!myPbrMat.NormalTexture.IsNull())
289   {
290     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.NormalTexture, Graphic3d_TextureUnit_Normal));
291   }
292   if (!myPbrMat.MetallicRoughnessTexture.IsNull())
293   {
294     aTextureSet->SetValue (aTexIter++, new XCAFPrs_Texture (*myPbrMat.MetallicRoughnessTexture, Graphic3d_TextureUnit_MetallicRoughness));
295   }
296
297   theAspect->SetTextureSet (aTextureSet);
298   theAspect->SetTextureMapOn (true);
299 }