1 // Author: Ilya Khramov
2 // Copyright (c) 2019 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <Graphic3d_PBRMaterial.hxx>
17 #include <Graphic3d_MaterialDefinitionError.hxx>
21 // =======================================================================
22 // function : RoughnessFromSpecular
24 // =======================================================================
25 Standard_ShortReal Graphic3d_PBRMaterial::RoughnessFromSpecular (const Quantity_Color& theSpecular,
26 const Standard_Real theShiness)
28 Standard_Real aRoughnessFactor = 1.0 - theShiness;
29 //Standard_Real aSpecIntens = theSpecular.Light() * theSpecular;
30 const Standard_Real aSpecIntens = theSpecular.Red() * 0.2125
31 + theSpecular.Green() * 0.7154
32 + theSpecular.Blue() * 0.0721;
33 if (aSpecIntens < 0.1)
35 // low specular intensity should produce a rough material even if shininess is high
36 aRoughnessFactor *= (1.0 - aSpecIntens);
38 return (Standard_ShortReal )aRoughnessFactor;
41 // =======================================================================
42 // function : Constructor
44 // =======================================================================
45 Graphic3d_PBRMaterial::Graphic3d_PBRMaterial ()
46 : myColor (0.f, 0.f, 0.f, 1.f),
53 // =======================================================================
54 // function : Constructor
56 // =======================================================================
57 Graphic3d_PBRMaterial::Graphic3d_PBRMaterial (const Graphic3d_BSDF& theBSDF)
62 // =======================================================================
63 // function : SetMetallic
65 // =======================================================================
66 void Graphic3d_PBRMaterial::SetMetallic (Standard_ShortReal theMetallic)
68 Graphic3d_MaterialDefinitionError_Raise_if (theMetallic < 0.f || theMetallic > 1.f,
69 "'metallic' parameter of PBR material must be in range [0, 1]")
70 myMetallic = theMetallic;
73 // =======================================================================
74 // function : Roughness
76 // =======================================================================
77 Standard_ShortReal Graphic3d_PBRMaterial::Roughness (Standard_ShortReal theNormalizedRoughness)
79 return theNormalizedRoughness * (1.f - MinRoughness()) + MinRoughness();
82 // =======================================================================
83 // function : SetRoughness
85 // =======================================================================
86 void Graphic3d_PBRMaterial::SetRoughness (Standard_ShortReal theRoughness)
88 Graphic3d_MaterialDefinitionError_Raise_if (theRoughness < 0.f || theRoughness > 1.f,
89 "'roughness' parameter of PBR material must be in range [0, 1]")
90 myRoughness = theRoughness;
93 // =======================================================================
96 // =======================================================================
97 void Graphic3d_PBRMaterial::SetIOR (Standard_ShortReal theIOR)
99 Graphic3d_MaterialDefinitionError_Raise_if (theIOR < 1.f || theIOR > 3.f,
100 "'IOR' parameter of PBR material must be in range [1, 3]")
104 // =======================================================================
105 // function : SetColor
107 // =======================================================================
108 void Graphic3d_PBRMaterial::SetColor (const Quantity_ColorRGBA& theColor)
110 myColor.SetRGB (theColor.GetRGB());
111 SetAlpha (theColor.Alpha());
114 // =======================================================================
115 // function : SetColor
117 // =======================================================================
118 void Graphic3d_PBRMaterial::SetColor (const Quantity_Color& theColor)
120 myColor.SetRGB (theColor);
123 // =======================================================================
124 // function : SetAlpha
126 // =======================================================================
127 void Graphic3d_PBRMaterial::SetAlpha (Standard_ShortReal theAlpha)
129 Graphic3d_MaterialDefinitionError_Raise_if (theAlpha < 0.f || theAlpha > 1.f,
130 "'alpha' parameter of PBR material must be in range [0, 1]")
131 myColor.SetAlpha (theAlpha);
134 // =======================================================================
135 // function : SetEmission
137 // =======================================================================
138 void Graphic3d_PBRMaterial::SetEmission (const Graphic3d_Vec3& theEmission)
140 Graphic3d_MaterialDefinitionError_Raise_if (theEmission.r() < 0.f
141 || theEmission.g() < 0.f
142 || theEmission.b() < 0.f,
143 "all components of 'emission' parameter of PBR material must be greater than 0")
144 myEmission = theEmission;
147 // =======================================================================
148 // function : SetBSDF
150 // =======================================================================
151 void Graphic3d_PBRMaterial::SetBSDF (const Graphic3d_BSDF& theBSDF)
153 SetEmission (theBSDF.Le);
155 if (theBSDF.Absorption != Graphic3d_Vec4(0.f))
158 SetColor (Quantity_Color (theBSDF.Absorption.rgb()));
159 if (theBSDF.FresnelCoat.FresnelType() == Graphic3d_FM_DIELECTRIC)
161 SetIOR (theBSDF.FresnelCoat.Serialize().y());
163 SetAlpha (theBSDF.Absorption.a() * 4.f);
168 if (theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_CONSTANT
169 && theBSDF.Kt != Graphic3d_Vec3(0.f))
174 SetColor (Quantity_Color (theBSDF.Kt));
175 SetAlpha (1.f - (theBSDF.Kt.r() + theBSDF.Kt.g() + theBSDF.Kt.b()) / 3.f);
179 SetRoughness(sqrtf (theBSDF.Ks.w()));
180 if (theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_DIELECTRIC
181 || theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_CONSTANT)
184 SetColor (Quantity_Color (theBSDF.Kd));
187 else if (theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_SCHLICK)
189 SetColor (Quantity_Color (theBSDF.FresnelBase.Serialize().rgb()));
194 SetColor (Quantity_Color (theBSDF.Ks.rgb()));
199 // =======================================================================
200 // function : GenerateEnvLUT
202 // =======================================================================
203 void Graphic3d_PBRMaterial::GenerateEnvLUT (const Handle(Image_PixMap)& theLUT,
204 unsigned int theNbIntegralSamples)
206 if (theLUT->Format() != Image_Format_RGF)
208 throw Standard_ProgramError("LUT pix map format for PBR LUT generation must be Image_Format_RGF");
211 for (unsigned int y = 0; y < theLUT->SizeY(); ++y)
213 Standard_ShortReal aRoughness = Roughness(y / Standard_ShortReal(theLUT->SizeY() - 1));
215 for (unsigned int x = 0; x < theLUT->SizeX(); ++x)
217 Standard_ShortReal aCosV = x / Standard_ShortReal(theLUT->SizeX() - 1);
218 Graphic3d_Vec3 aView = lutGenView (aCosV);
219 unsigned int aCount = 0;
220 Graphic3d_Vec2 aResult = Graphic3d_Vec2 (0.f);
221 for (unsigned int i = 0; i < theNbIntegralSamples; ++i)
223 Graphic3d_Vec2 aHammersleyPoint = lutGenHammersley (i, theNbIntegralSamples);
224 Graphic3d_Vec3 aHalf = lutGenImportanceSample (aHammersleyPoint, aRoughness);
225 Graphic3d_Vec3 aLight = lutGenReflect (aView, aHalf);
226 if (aLight.z() >= 0.f)
229 Standard_ShortReal aCosVH = aView.Dot (aHalf);
230 Standard_ShortReal aGeometryFactor = lutGenGeometryFactor (aLight.z(),
233 Standard_ShortReal anIntermediateResult = 1.f - aCosVH;
234 anIntermediateResult *= anIntermediateResult;
235 anIntermediateResult *= anIntermediateResult;
236 anIntermediateResult *= 1.f - aCosVH;
238 aResult.x() += aGeometryFactor * (aCosVH / aHalf.z()) * (1.f - anIntermediateResult);
239 aResult.y() += aGeometryFactor * (aCosVH / aHalf.z()) * anIntermediateResult;
243 aResult = aResult / Standard_ShortReal(theNbIntegralSamples);
244 theLUT->ChangeValue<Graphic3d_Vec2> (theLUT->SizeY() - 1 - y, x) = aResult;
249 // =======================================================================
250 // function : SpecIBLMapSamplesFactor
252 // =======================================================================
253 Standard_ShortReal Graphic3d_PBRMaterial::SpecIBLMapSamplesFactor (Standard_ShortReal theProbability,
254 Standard_ShortReal theRoughness)
256 return acosf (lutGenImportanceSampleCosTheta (theProbability, theRoughness)) * 2.f / Standard_ShortReal(M_PI);
259 // =======================================================================
260 // function : lutGenGeometryFactor
262 // =======================================================================
263 Standard_ShortReal Graphic3d_PBRMaterial::lutGenGeometryFactor (Standard_ShortReal theCosL,
264 Standard_ShortReal theCosV,
265 Standard_ShortReal theRoughness)
267 Standard_ShortReal aK = theRoughness * theRoughness * 0.5f;
269 Standard_ShortReal aGeometryFactor = theCosL;
270 aGeometryFactor /= theCosL * (1.f - aK) + aK;
271 aGeometryFactor /= theCosV * (1.f - aK) + aK;
273 return aGeometryFactor;
276 // =======================================================================
277 // function : lutGenHammersley
279 // =======================================================================
280 Graphic3d_Vec2 Graphic3d_PBRMaterial::lutGenHammersley (unsigned int theNumber, unsigned int theCount)
282 Standard_ShortReal aPhi2 = 0.f;
283 for (unsigned int i = 0; i < sizeof(unsigned int) * 8; ++i)
285 if ((theNumber >> i) == 0)
289 aPhi2 += ((theNumber >> i) & 1) / Standard_ShortReal(1 << (i + 1));
292 return Graphic3d_Vec2(theNumber / Standard_ShortReal(theCount), aPhi2);
295 // =======================================================================
296 // function : lutGenImportanceSampleCosTheta
298 // =======================================================================
299 Standard_ShortReal Graphic3d_PBRMaterial::lutGenImportanceSampleCosTheta (Standard_ShortReal theHammersleyPointComponent,
300 Standard_ShortReal theRoughness)
302 Standard_ShortReal aQuadRoughness = theRoughness * theRoughness;
303 aQuadRoughness *= aQuadRoughness;
305 Standard_ShortReal aTmp = 1.f + (aQuadRoughness - 1.f) * theHammersleyPointComponent;
309 return sqrtf ((1.f - theHammersleyPointComponent) / aTmp);
317 // =======================================================================
318 // function : lutGenImportanceSample
320 // =======================================================================
321 Graphic3d_Vec3 Graphic3d_PBRMaterial::lutGenImportanceSample (const Graphic3d_Vec2 &theHammerslayPoint,
322 Standard_ShortReal theRoughness)
324 Standard_ShortReal aPhi = 2.f * Standard_ShortReal(M_PI) * theHammerslayPoint.y();
326 Standard_ShortReal aCosTheta = lutGenImportanceSampleCosTheta (theHammerslayPoint.x(), theRoughness);
327 Standard_ShortReal aSinTheta = sqrtf (1.f - aCosTheta * aCosTheta);
329 return Graphic3d_Vec3(aSinTheta * cosf (aPhi),
330 aSinTheta * sinf (aPhi),
334 // =======================================================================
335 // function : lutGenView
337 // =======================================================================
338 Graphic3d_Vec3 Graphic3d_PBRMaterial::lutGenView (Standard_ShortReal theCosV)
340 return Graphic3d_Vec3(0.f, sqrtf(1.f - theCosV * theCosV), theCosV);
343 // =======================================================================
344 // function : lutGenReflect
346 // =======================================================================
347 Graphic3d_Vec3 Graphic3d_PBRMaterial::lutGenReflect (const Graphic3d_Vec3 &theVector,
348 const Graphic3d_Vec3 &theAxis)
350 return theAxis * theAxis.Dot(theVector) * 2.f - theVector;