0030700: Visualization, TKOpenGl - support PBR Metallic-Roughness shading model
[occt.git] / src / Graphic3d / Graphic3d_BSDF.cxx
1 // Created on: 2015-01-19
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Graphic3d_BSDF.hxx>
17
18 #include <Graphic3d_PBRMaterial.hxx>
19
20 #include <algorithm>
21
22 // =======================================================================
23 // function : Serialize
24 // purpose  :
25 // =======================================================================
26 Graphic3d_Vec4 Graphic3d_Fresnel::Serialize() const
27 {
28   Graphic3d_Vec4 aData = Graphic3d_Vec4 (myFresnelData, 0.f);
29
30   if (myFresnelType != Graphic3d_FM_SCHLICK)
31   {
32     aData.x() = -static_cast<float> (myFresnelType);
33   }
34
35   return aData;
36 }
37
38 // =======================================================================
39 // function : fresnelNormal
40 // purpose  :
41 // =======================================================================
42 inline float fresnelNormal (float theN,
43                             float theK)
44 {
45   return ((theN - 1.f) * (theN - 1.f) + theK * theK) /
46          ((theN + 1.f) * (theN + 1.f) + theK * theK);
47 }
48
49 // =======================================================================
50 // function : CreateConductor
51 // purpose  :
52 // =======================================================================
53 Graphic3d_Fresnel Graphic3d_Fresnel::CreateConductor (const Graphic3d_Vec3& theRefractionIndex,
54                                                       const Graphic3d_Vec3& theAbsorptionIndex)
55 {
56   const Graphic3d_Vec3 aFresnel (fresnelNormal (theRefractionIndex.x(), theAbsorptionIndex.x()),
57                                  fresnelNormal (theRefractionIndex.y(), theAbsorptionIndex.y()),
58                                  fresnelNormal (theRefractionIndex.z(), theAbsorptionIndex.z()));
59
60   return Graphic3d_Fresnel (Graphic3d_FM_SCHLICK, aFresnel);
61 }
62
63 // =======================================================================
64 // function : Graphic3d_BSDF
65 // purpose  :
66 // =======================================================================
67 Graphic3d_BSDF::Graphic3d_BSDF()
68 : Ks (Graphic3d_Vec3 (0.f), 1.f)
69 {
70   FresnelCoat = Graphic3d_Fresnel::CreateConstant (0.f);
71   FresnelBase = Graphic3d_Fresnel::CreateConstant (1.f);
72 }
73
74 // =======================================================================
75 // function : operator==
76 // purpose  :
77 // =======================================================================
78 bool Graphic3d_BSDF::operator== (const Graphic3d_BSDF& theOther) const
79 {
80   return Kc          == theOther.Kc
81       && Kd          == theOther.Kd
82       && Kt          == theOther.Kt
83       && Ks          == theOther.Ks
84       && Le          == theOther.Le
85       && Absorption  == theOther.Absorption
86       && FresnelCoat == theOther.FresnelCoat
87       && FresnelBase == theOther.FresnelBase;
88 }
89
90 // =======================================================================
91 // function : Normalize
92 // purpose  :
93 // =======================================================================
94 void Graphic3d_BSDF::Normalize()
95 {
96   float aMax = 0.f;
97
98   for (int aChannelID = 0; aChannelID < 3; ++aChannelID)
99   {
100     aMax = std::max (aMax, Kd[aChannelID] + Ks[aChannelID] + Kt[aChannelID]);
101   }
102
103   if (aMax > 1.f)
104   {
105     for (int aChannelID = 0; aChannelID < 3; ++aChannelID)
106     {
107       Kd[aChannelID] /= aMax;
108       Ks[aChannelID] /= aMax;
109       Kt[aChannelID] /= aMax;
110     }
111   }
112 }
113
114 // =======================================================================
115 // function : CreateDiffuse
116 // purpose  :
117 // =======================================================================
118 Graphic3d_BSDF Graphic3d_BSDF::CreateDiffuse (const Graphic3d_Vec3& theWeight)
119 {
120   Graphic3d_BSDF aBSDF;
121
122   aBSDF.Kd = theWeight;
123
124   return aBSDF;
125 }
126
127 // =======================================================================
128 // function : CreateMetallic
129 // purpose  :
130 // =======================================================================
131 Graphic3d_BSDF Graphic3d_BSDF::CreateMetallic (const Graphic3d_Vec3& theWeight, const Graphic3d_Fresnel& theFresnel, const float theRoughness)
132 {
133   Graphic3d_BSDF aBSDF;
134
135   aBSDF.FresnelBase = theFresnel;
136
137   // Selecting between specular and glossy
138   // BRDF depending on the given roughness
139   aBSDF.Ks = Graphic3d_Vec4 (theWeight, theRoughness);
140
141   return aBSDF;
142 }
143
144 // =======================================================================
145 // function : CreateTransparent
146 // purpose  :
147 // =======================================================================
148 Graphic3d_BSDF Graphic3d_BSDF::CreateTransparent (const Graphic3d_Vec3& theWeight,
149                                                   const Graphic3d_Vec3& theAbsorptionColor,
150                                                   const float           theAbsorptionCoeff)
151 {
152   Graphic3d_BSDF aBSDF;
153
154   // Create Fresnel parameters for the coat layer;
155   // set it to 0 value to simulate ideal refractor
156   aBSDF.FresnelCoat = Graphic3d_Fresnel::CreateConstant (0.f);
157
158   aBSDF.Kt = theWeight;
159
160   // Link reflection and transmission coefficients
161   aBSDF.Kc.r() = aBSDF.Kt.r();
162   aBSDF.Kc.g() = aBSDF.Kt.g();
163   aBSDF.Kc.b() = aBSDF.Kt.b();
164
165   aBSDF.Absorption = Graphic3d_Vec4 (theAbsorptionColor,
166                                      theAbsorptionCoeff);
167
168   return aBSDF;
169 }
170
171 // =======================================================================
172 // function : CreateGlass
173 // purpose  :
174 // =======================================================================
175 Graphic3d_BSDF Graphic3d_BSDF::CreateGlass (const Graphic3d_Vec3& theWeight,
176                                             const Graphic3d_Vec3& theAbsorptionColor,
177                                             const float           theAbsorptionCoeff,
178                                             const float           theRefractionIndex)
179 {
180   Graphic3d_BSDF aBSDF;
181
182   // Create Fresnel parameters for the coat layer
183   aBSDF.FresnelCoat = Graphic3d_Fresnel::CreateDielectric (theRefractionIndex);
184
185   aBSDF.Kt = theWeight;
186
187   aBSDF.Kc.r() = aBSDF.Kt.r();
188   aBSDF.Kc.g() = aBSDF.Kt.g();
189   aBSDF.Kc.b() = aBSDF.Kt.b();
190
191   aBSDF.Absorption = Graphic3d_Vec4 (theAbsorptionColor,
192                                      theAbsorptionCoeff);
193
194   return aBSDF;
195 }
196
197 // =======================================================================
198 // function : CreateMetallicRoughness
199 // purpose  :
200 // =======================================================================
201 Graphic3d_BSDF Graphic3d_BSDF::CreateMetallicRoughness (const Graphic3d_PBRMaterial& thePbr)
202 {
203   const Graphic3d_Vec3 aDiff = (Graphic3d_Vec3 )thePbr.Color().GetRGB() * thePbr.Alpha();
204   const Standard_ShortReal aRougness2 = thePbr.NormalizedRoughness() * thePbr.NormalizedRoughness();
205
206   Graphic3d_BSDF aBsdf;
207   aBsdf.FresnelBase = Graphic3d_Fresnel::CreateSchlick (aDiff * thePbr.Metallic());
208   aBsdf.Ks.SetValues (Graphic3d_Vec3 (thePbr.Alpha()), aRougness2);
209   aBsdf.Kt = Graphic3d_Vec3 (1.0f - thePbr.Alpha());
210   aBsdf.Kd = aDiff * (1.0f - thePbr.Metallic());
211   return aBsdf;
212 }