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