0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[occt.git] / src / Graphic3d / Graphic3d_PBRMaterial.cxx
CommitLineData
67312b79 1// Author: Ilya Khramov
2// Copyright (c) 2019 OPEN CASCADE SAS
3//
4// This file is part of Open CASCADE Technology software library.
5//
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.
11//
12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
14
15#include <Graphic3d_PBRMaterial.hxx>
16
17#include <Graphic3d_MaterialDefinitionError.hxx>
18
19#include <limits>
20
21// =======================================================================
22// function : RoughnessFromSpecular
23// purpose :
24// =======================================================================
25Standard_ShortReal Graphic3d_PBRMaterial::RoughnessFromSpecular (const Quantity_Color& theSpecular,
26 const Standard_Real theShiness)
27{
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)
34 {
35 // low specular intensity should produce a rough material even if shininess is high
36 aRoughnessFactor *= (1.0 - aSpecIntens);
37 }
38 return (Standard_ShortReal )aRoughnessFactor;
39}
40
41// =======================================================================
42// function : Constructor
43// purpose :
44// =======================================================================
45Graphic3d_PBRMaterial::Graphic3d_PBRMaterial ()
46: myColor (0.f, 0.f, 0.f, 1.f),
47 myMetallic (0.f),
48 myRoughness (1.f),
49 myEmission (0.f),
50 myIOR (1.5f)
51{}
52
53// =======================================================================
54// function : Constructor
55// purpose :
56// =======================================================================
57Graphic3d_PBRMaterial::Graphic3d_PBRMaterial (const Graphic3d_BSDF& theBSDF)
58{
59 SetBSDF (theBSDF);
60}
61
62// =======================================================================
63// function : SetMetallic
64// purpose :
65// =======================================================================
66void Graphic3d_PBRMaterial::SetMetallic (Standard_ShortReal theMetallic)
67{
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;
71}
72
73// =======================================================================
74// function : Roughness
75// purpose :
76// =======================================================================
77Standard_ShortReal Graphic3d_PBRMaterial::Roughness (Standard_ShortReal theNormalizedRoughness)
78{
79 return theNormalizedRoughness * (1.f - MinRoughness()) + MinRoughness();
80}
81
82// =======================================================================
83// function : SetRoughness
84// purpose :
85// =======================================================================
86void Graphic3d_PBRMaterial::SetRoughness (Standard_ShortReal theRoughness)
87{
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;
91}
92
93// =======================================================================
94// function : SetIOR
95// purpose :
96// =======================================================================
97void Graphic3d_PBRMaterial::SetIOR (Standard_ShortReal theIOR)
98{
99 Graphic3d_MaterialDefinitionError_Raise_if (theIOR < 1.f || theIOR > 3.f,
100 "'IOR' parameter of PBR material must be in range [1, 3]")
101 myIOR = theIOR;
102}
103
104// =======================================================================
105// function : SetColor
106// purpose :
107// =======================================================================
108void Graphic3d_PBRMaterial::SetColor (const Quantity_ColorRGBA& theColor)
109{
110 myColor.SetRGB (theColor.GetRGB());
111 SetAlpha (theColor.Alpha());
112}
113
114// =======================================================================
115// function : SetColor
116// purpose :
117// =======================================================================
118void Graphic3d_PBRMaterial::SetColor (const Quantity_Color& theColor)
119{
120 myColor.SetRGB (theColor);
121}
122
123// =======================================================================
124// function : SetAlpha
125// purpose :
126// =======================================================================
127void Graphic3d_PBRMaterial::SetAlpha (Standard_ShortReal theAlpha)
128{
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);
132}
133
134// =======================================================================
135// function : SetEmission
136// purpose :
137// =======================================================================
138void Graphic3d_PBRMaterial::SetEmission (const Graphic3d_Vec3& theEmission)
139{
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;
145}
146
147// =======================================================================
148// function : SetBSDF
149// purpose :
150// =======================================================================
151void Graphic3d_PBRMaterial::SetBSDF (const Graphic3d_BSDF& theBSDF)
152{
153 SetEmission (theBSDF.Le);
154
155 if (theBSDF.Absorption != Graphic3d_Vec4(0.f))
156 {
157 SetMetallic (0.f);
158 SetColor (Quantity_Color (theBSDF.Absorption.rgb()));
159 if (theBSDF.FresnelCoat.FresnelType() == Graphic3d_FM_DIELECTRIC)
160 {
161 SetIOR (theBSDF.FresnelCoat.Serialize().y());
162 SetRoughness (0.f);
163 SetAlpha (theBSDF.Absorption.a() * 4.f);
164 }
165 return;
166 }
167
168 if (theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_CONSTANT
169 && theBSDF.Kt != Graphic3d_Vec3(0.f))
170 {
171 SetIOR (1.f);
172 SetRoughness (1.f);
173 SetMetallic (0.f);
174 SetColor (Quantity_Color (theBSDF.Kt));
175 SetAlpha (1.f - (theBSDF.Kt.r() + theBSDF.Kt.g() + theBSDF.Kt.b()) / 3.f);
176 return;
177 }
178
179 SetRoughness(sqrtf (theBSDF.Ks.w()));
180 if (theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_DIELECTRIC
181 || theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_CONSTANT)
182 {
183 SetIOR (1.5f);
184 SetColor (Quantity_Color (theBSDF.Kd));
185 SetMetallic (0.f);
186 }
187 else if (theBSDF.FresnelBase.FresnelType() == Graphic3d_FM_SCHLICK)
188 {
189 SetColor (Quantity_Color (theBSDF.FresnelBase.Serialize().rgb()));
190 SetMetallic (1.f);
191 }
192 else
193 {
194 SetColor (Quantity_Color (theBSDF.Ks.rgb()));
195 SetMetallic (1.f);
196 }
197}
198
199// =======================================================================
200// function : GenerateEnvLUT
201// purpose :
202// =======================================================================
203void Graphic3d_PBRMaterial::GenerateEnvLUT (const Handle(Image_PixMap)& theLUT,
204 unsigned int theNbIntegralSamples)
205{
206 if (theLUT->Format() != Image_Format_RGF)
207 {
208 throw Standard_ProgramError("LUT pix map format for PBR LUT generation must be Image_Format_RGF");
209 }
210
211 for (unsigned int y = 0; y < theLUT->SizeY(); ++y)
212 {
213 Standard_ShortReal aRoughness = Roughness(y / Standard_ShortReal(theLUT->SizeY() - 1));
214
215 for (unsigned int x = 0; x < theLUT->SizeX(); ++x)
216 {
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)
222 {
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)
227 {
228 ++aCount;
229 Standard_ShortReal aCosVH = aView.Dot (aHalf);
230 Standard_ShortReal aGeometryFactor = lutGenGeometryFactor (aLight.z(),
231 aCosV,
232 aRoughness);
233 Standard_ShortReal anIntermediateResult = 1.f - aCosVH;
234 anIntermediateResult *= anIntermediateResult;
235 anIntermediateResult *= anIntermediateResult;
236 anIntermediateResult *= 1.f - aCosVH;
237
238 aResult.x() += aGeometryFactor * (aCosVH / aHalf.z()) * (1.f - anIntermediateResult);
239 aResult.y() += aGeometryFactor * (aCosVH / aHalf.z()) * anIntermediateResult;
240 }
241 }
242
243 aResult = aResult / Standard_ShortReal(theNbIntegralSamples);
244 theLUT->ChangeValue<Graphic3d_Vec2> (theLUT->SizeY() - 1 - y, x) = aResult;
245 }
246 }
247}
248
249// =======================================================================
250// function : SpecIBLMapSamplesFactor
251// purpose :
252// =======================================================================
253Standard_ShortReal Graphic3d_PBRMaterial::SpecIBLMapSamplesFactor (Standard_ShortReal theProbability,
254 Standard_ShortReal theRoughness)
255{
256 return acosf (lutGenImportanceSampleCosTheta (theProbability, theRoughness)) * 2.f / Standard_ShortReal(M_PI);
257}
258
259// =======================================================================
260// function : lutGenGeometryFactor
261// purpose :
262// =======================================================================
263Standard_ShortReal Graphic3d_PBRMaterial::lutGenGeometryFactor (Standard_ShortReal theCosL,
264 Standard_ShortReal theCosV,
265 Standard_ShortReal theRoughness)
266{
267 Standard_ShortReal aK = theRoughness * theRoughness * 0.5f;
268
269 Standard_ShortReal aGeometryFactor = theCosL;
270 aGeometryFactor /= theCosL * (1.f - aK) + aK;
271 aGeometryFactor /= theCosV * (1.f - aK) + aK;
272
273 return aGeometryFactor;
274}
275
276// =======================================================================
277// function : lutGenHammersley
278// purpose :
279// =======================================================================
280Graphic3d_Vec2 Graphic3d_PBRMaterial::lutGenHammersley (unsigned int theNumber, unsigned int theCount)
281{
282 Standard_ShortReal aPhi2 = 0.f;
283 for (unsigned int i = 0; i < sizeof(unsigned int) * 8; ++i)
284 {
285 if ((theNumber >> i) == 0)
286 {
287 break;
288 }
289 aPhi2 += ((theNumber >> i) & 1) / Standard_ShortReal(1 << (i + 1));
290 }
291
292 return Graphic3d_Vec2(theNumber / Standard_ShortReal(theCount), aPhi2);
293}
294
295// =======================================================================
296// function : lutGenImportanceSampleCosTheta
297// purpose :
298// =======================================================================
299Standard_ShortReal Graphic3d_PBRMaterial::lutGenImportanceSampleCosTheta (Standard_ShortReal theHammersleyPointComponent,
300 Standard_ShortReal theRoughness)
301{
302 Standard_ShortReal aQuadRoughness = theRoughness * theRoughness;
303 aQuadRoughness *= aQuadRoughness;
304
305 Standard_ShortReal aTmp = 1.f + (aQuadRoughness - 1.f) * theHammersleyPointComponent;
306
307 if (aTmp != 0.f)
308 {
309 return sqrtf ((1.f - theHammersleyPointComponent) / aTmp);
310 }
311 else
312 {
313 return 0.f;
314 }
315}
316
317// =======================================================================
318// function : lutGenImportanceSample
319// purpose :
320// =======================================================================
321Graphic3d_Vec3 Graphic3d_PBRMaterial::lutGenImportanceSample (const Graphic3d_Vec2 &theHammerslayPoint,
322 Standard_ShortReal theRoughness)
323{
324 Standard_ShortReal aPhi = 2.f * Standard_ShortReal(M_PI) * theHammerslayPoint.y();
325
326 Standard_ShortReal aCosTheta = lutGenImportanceSampleCosTheta (theHammerslayPoint.x(), theRoughness);
327 Standard_ShortReal aSinTheta = sqrtf (1.f - aCosTheta * aCosTheta);
328
329 return Graphic3d_Vec3(aSinTheta * cosf (aPhi),
330 aSinTheta * sinf (aPhi),
331 aCosTheta);
332}
333
334// =======================================================================
335// function : lutGenView
336// purpose :
337// =======================================================================
338Graphic3d_Vec3 Graphic3d_PBRMaterial::lutGenView (Standard_ShortReal theCosV)
339{
340 return Graphic3d_Vec3(0.f, sqrtf(1.f - theCosV * theCosV), theCosV);
341}
342
343// =======================================================================
344// function : lutGenReflect
345// purpose :
346// =======================================================================
347Graphic3d_Vec3 Graphic3d_PBRMaterial::lutGenReflect (const Graphic3d_Vec3 &theVector,
348 const Graphic3d_Vec3 &theAxis)
349{
350 return theAxis * theAxis.Dot(theVector) * 2.f - theVector;
351}
bc73b006 352
353//=======================================================================
354//function : DumpJson
355//purpose :
356//=======================================================================
357void Graphic3d_PBRMaterial::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
358{
359 OCCT_DUMP_CLASS_BEGIN (theOStream, Graphic3d_PBRMaterial)
360
361 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myColor)
362
363 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMetallic)
364 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRoughness)
365 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myEmission)
366 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIOR)
367}