0031618: Data Exchange, RWGltf_CafWriter - exporting some models produces glTF files...
[occt.git] / src / RWGltf / RWGltf_GltfMaterialMap.cxx
CommitLineData
01b2f506 1// Copyright (c) 2017-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 <RWGltf_GltfMaterialMap.hxx>
15
16#include <RWGltf_GltfRootElement.hxx>
17
18#ifdef HAVE_RAPIDJSON
19 #include <RWGltf_GltfOStreamWriter.hxx>
20#endif
21
22// =======================================================================
23// function : baseColorTexture
24// purpose :
25// =======================================================================
26const Handle(Image_Texture)& RWGltf_GltfMaterialMap::baseColorTexture (const Handle(XCAFDoc_VisMaterial)& theMat)
27{
28 static const Handle(Image_Texture) THE_NULL_TEXTURE;
29 if (theMat.IsNull())
30 {
31 return THE_NULL_TEXTURE;
32 }
33 else if (theMat->HasPbrMaterial()
34 && !theMat->PbrMaterial().BaseColorTexture.IsNull())
35 {
36 return theMat->PbrMaterial().BaseColorTexture;
37 }
38 else if (theMat->HasCommonMaterial()
39 && !theMat->CommonMaterial().DiffuseTexture.IsNull())
40 {
41 return theMat->CommonMaterial().DiffuseTexture;
42 }
43 return THE_NULL_TEXTURE;
44}
45
46// =======================================================================
47// function : RWGltf_GltfMaterialMap
48// purpose :
49// =======================================================================
50RWGltf_GltfMaterialMap::RWGltf_GltfMaterialMap (const TCollection_AsciiString& theFile,
51 const Standard_Integer theDefSamplerId)
52: RWMesh_MaterialMap (theFile),
53 myWriter (NULL),
54 myDefSamplerId (theDefSamplerId),
55 myNbImages (0)
56{
57 myMatNameAsKey = false;
58}
59
60// =======================================================================
61// function : ~RWGltf_GltfMaterialMap
62// purpose :
63// =======================================================================
64RWGltf_GltfMaterialMap::~RWGltf_GltfMaterialMap()
65{
66 //
67}
68
69// =======================================================================
70// function : AddImages
71// purpose :
72// =======================================================================
73void RWGltf_GltfMaterialMap::AddImages (RWGltf_GltfOStreamWriter* theWriter,
74 const XCAFPrs_Style& theStyle,
75 Standard_Boolean& theIsStarted)
76{
77 if (theWriter == NULL
78 || theStyle.Material().IsNull()
79 || theStyle.Material()->IsEmpty())
80 {
81 return;
82 }
83
84 addImage (theWriter, baseColorTexture (theStyle.Material()), theIsStarted);
85 addImage (theWriter, theStyle.Material()->PbrMaterial().MetallicRoughnessTexture, theIsStarted);
86 addImage (theWriter, theStyle.Material()->PbrMaterial().NormalTexture, theIsStarted);
87 addImage (theWriter, theStyle.Material()->PbrMaterial().EmissiveTexture, theIsStarted);
88 addImage (theWriter, theStyle.Material()->PbrMaterial().OcclusionTexture, theIsStarted);
89}
90
91// =======================================================================
92// function : addImage
93// purpose :
94// =======================================================================
95void RWGltf_GltfMaterialMap::addImage (RWGltf_GltfOStreamWriter* theWriter,
96 const Handle(Image_Texture)& theTexture,
97 Standard_Boolean& theIsStarted)
98{
99#ifdef HAVE_RAPIDJSON
100 if (theTexture.IsNull()
101 || myImageMap.IsBound1 (theTexture)
102 || myImageFailMap.Contains (theTexture))
103 {
104 return;
105 }
106
107 TCollection_AsciiString aGltfImgKey = myNbImages;
108 ++myNbImages;
109 for (; myImageMap.IsBound2 (aGltfImgKey); ++myNbImages)
110 {
111 aGltfImgKey = myNbImages;
112 }
113
114 TCollection_AsciiString aTextureUri;
115 if (!CopyTexture (aTextureUri, theTexture, aGltfImgKey))
116 {
117 myImageFailMap.Add (theTexture);
118 return;
119 }
120
121 myImageMap.Bind (theTexture, aGltfImgKey);
122
123 if (!theIsStarted)
124 {
125 theWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_Images));
126 theWriter->StartArray();
127 theIsStarted = true;
128 }
129
130 theWriter->StartObject();
131 {
132 theWriter->Key ("uri");
133 theWriter->String (aTextureUri.ToCString());
134 }
135 theWriter->EndObject();
136#else
137 (void )theWriter;
138 (void )theTexture;
139 (void )theIsStarted;
140#endif
141}
142
143// =======================================================================
144// function : AddMaterial
145// purpose :
146// =======================================================================
147void RWGltf_GltfMaterialMap::AddMaterial (RWGltf_GltfOStreamWriter* theWriter,
148 const XCAFPrs_Style& theStyle,
149 Standard_Boolean& theIsStarted)
150{
151#ifdef HAVE_RAPIDJSON
152 if (theWriter == NULL
153 || ((theStyle.Material().IsNull() || theStyle.Material()->IsEmpty())
154 && !theStyle.IsSetColorSurf()))
155 {
156 return;
157 }
158
159 if (!theIsStarted)
160 {
161 theWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_Materials));
162 theWriter->StartArray();
163 theIsStarted = true;
164 }
165 myWriter = theWriter;
166 AddMaterial (theStyle);
167 myWriter = NULL;
168#else
169 (void )theWriter;
170 (void )theStyle;
171 (void )theIsStarted;
172#endif
173}
174
175// =======================================================================
176// function : AddTextures
177// purpose :
178// =======================================================================
179void RWGltf_GltfMaterialMap::AddTextures (RWGltf_GltfOStreamWriter* theWriter,
180 const XCAFPrs_Style& theStyle,
181 Standard_Boolean& theIsStarted)
182{
183 if (theWriter == NULL
184 || theStyle.Material().IsNull()
185 || theStyle.Material()->IsEmpty())
186 {
187 return;
188 }
189
190 addTexture (theWriter, baseColorTexture (theStyle.Material()), theIsStarted);
191 addTexture (theWriter, theStyle.Material()->PbrMaterial().MetallicRoughnessTexture, theIsStarted);
192 addTexture (theWriter, theStyle.Material()->PbrMaterial().NormalTexture, theIsStarted);
193 addTexture (theWriter, theStyle.Material()->PbrMaterial().EmissiveTexture, theIsStarted);
194 addTexture (theWriter, theStyle.Material()->PbrMaterial().OcclusionTexture, theIsStarted);
195}
196
197// =======================================================================
198// function : addTexture
199// purpose :
200// =======================================================================
201void RWGltf_GltfMaterialMap::addTexture (RWGltf_GltfOStreamWriter* theWriter,
202 const Handle(Image_Texture)& theTexture,
203 Standard_Boolean& theIsStarted)
204{
205#ifdef HAVE_RAPIDJSON
206 if (theTexture.IsNull()
207 || myTextureMap.Contains (theTexture)
208 || !myImageMap .IsBound1 (theTexture))
209 {
210 return;
211 }
212
213 const TCollection_AsciiString anImgKey = myImageMap.Find1 (theTexture);
214 myTextureMap.Add (theTexture);
215 if (anImgKey.IsEmpty())
216 {
217 return;
218 }
219
220 if (!theIsStarted)
221 {
222 theWriter->Key (RWGltf_GltfRootElementName (RWGltf_GltfRootElement_Textures));
223 theWriter->StartArray();
224 theIsStarted = true;
225 }
226
227 theWriter->StartObject();
228 {
229 theWriter->Key ("sampler");
230 theWriter->Int (myDefSamplerId); // mandatory field by specs
231 theWriter->Key ("source");
232 theWriter->Int (anImgKey.IntegerValue());
233 }
234 theWriter->EndObject();
235#else
236 (void )theWriter;
237 (void )theTexture;
238 (void )theIsStarted;
239#endif
240}
241
242// =======================================================================
243// function : AddMaterial
244// purpose :
245// =======================================================================
246TCollection_AsciiString RWGltf_GltfMaterialMap::AddMaterial (const XCAFPrs_Style& theStyle)
247{
248 return RWMesh_MaterialMap::AddMaterial (theStyle);
249}
250
251// =======================================================================
252// function : DefineMaterial
253// purpose :
254// =======================================================================
255void RWGltf_GltfMaterialMap::DefineMaterial (const XCAFPrs_Style& theStyle,
256 const TCollection_AsciiString& /*theKey*/,
257 const TCollection_AsciiString& theName)
258{
259#ifdef HAVE_RAPIDJSON
260 if (myWriter == NULL)
261 {
262 Standard_ProgramError::Raise ("RWGltf_GltfMaterialMap::DefineMaterial() should be called with JSON Writer");
263 return;
264 }
265
266 XCAFDoc_VisMaterialPBR aPbrMat;
267 const bool hasMaterial = !theStyle.Material().IsNull()
268 && !theStyle.Material()->IsEmpty();
269 if (hasMaterial)
270 {
271 aPbrMat = theStyle.Material()->ConvertToPbrMaterial();
272 }
273 else if (!myDefaultStyle.Material().IsNull()
274 && myDefaultStyle.Material()->HasPbrMaterial())
275 {
276 aPbrMat = myDefaultStyle.Material()->PbrMaterial();
277 }
278 if (theStyle.IsSetColorSurf())
279 {
280 aPbrMat.BaseColor.SetRGB (theStyle.GetColorSurf());
281 if (theStyle.GetColorSurfRGBA().Alpha() < 1.0f)
282 {
283 aPbrMat.BaseColor.SetAlpha (theStyle.GetColorSurfRGBA().Alpha());
284 }
285 }
286 myWriter->StartObject();
287 {
288 myWriter->Key ("name");
289 myWriter->String (theName.ToCString());
290
291 myWriter->Key ("pbrMetallicRoughness");
292 myWriter->StartObject();
293 {
294 myWriter->Key ("baseColorFactor");
295 myWriter->StartArray();
296 {
297 myWriter->Double (aPbrMat.BaseColor.GetRGB().Red());
298 myWriter->Double (aPbrMat.BaseColor.GetRGB().Green());
299 myWriter->Double (aPbrMat.BaseColor.GetRGB().Blue());
300 myWriter->Double (aPbrMat.BaseColor.Alpha());
301 }
302 myWriter->EndArray();
303
304 if (const Handle(Image_Texture)& aBaseTexture = baseColorTexture (theStyle.Material()))
305 {
306 if (myImageMap.IsBound1 (aBaseTexture))
307 {
308 myWriter->Key ("baseColorTexture");
309 myWriter->StartObject();
310 {
311 myWriter->Key ("index");
312 const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aBaseTexture);
313 if (!anImageIdx.IsEmpty())
314 {
315 myWriter->Int (anImageIdx.IntegerValue());
316 }
317 }
318 myWriter->EndObject();
319 }
320 }
321
322 if (hasMaterial
323 || aPbrMat.Metallic != 1.0f)
324 {
325 myWriter->Key ("metallicFactor");
326 myWriter->Double (aPbrMat.Metallic);
327 }
328
329 if (!aPbrMat.MetallicRoughnessTexture.IsNull()
330 && myImageMap.IsBound1 (aPbrMat.MetallicRoughnessTexture))
331 {
332 myWriter->Key ("metallicRoughnessTexture");
333 myWriter->StartObject();
334 {
335 myWriter->Key ("index");
336 const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.MetallicRoughnessTexture);
337 if (!anImageIdx.IsEmpty())
338 {
339 myWriter->Int (anImageIdx.IntegerValue());
340 }
341 }
342 myWriter->EndObject();
343 }
344
345 if (hasMaterial
346 || aPbrMat.Roughness != 1.0f)
347 {
348 myWriter->Key ("roughnessFactor");
349 myWriter->Double (aPbrMat.Roughness);
350 }
351 }
352 myWriter->EndObject();
353
354 if (theStyle.Material().IsNull()
355 || theStyle.Material()->IsDoubleSided())
356 {
357 myWriter->Key ("doubleSided");
358 myWriter->Bool (true);
359 }
360
361 const Graphic3d_AlphaMode anAlphaMode = !theStyle.Material().IsNull() ? theStyle.Material()->AlphaMode() : Graphic3d_AlphaMode_BlendAuto;
362 switch (anAlphaMode)
363 {
364 case Graphic3d_AlphaMode_BlendAuto:
365 {
366 if (aPbrMat.BaseColor.Alpha() < 1.0f)
367 {
368 myWriter->Key ("alphaMode");
369 myWriter->String ("BLEND");
370 }
371 break;
372 }
373 case Graphic3d_AlphaMode_Opaque:
374 {
375 break;
376 }
377 case Graphic3d_AlphaMode_Mask:
378 {
379 myWriter->Key ("alphaMode");
380 myWriter->String ("MASK");
381 break;
382 }
383 case Graphic3d_AlphaMode_Blend:
384 {
385 myWriter->Key ("alphaMode");
386 myWriter->String ("BLEND");
387 break;
388 }
389 }
390 if (!theStyle.Material().IsNull()
391 && theStyle.Material()->AlphaCutOff() != 0.5f)
392 {
393 myWriter->Key ("alphaCutoff");
394 myWriter->Double (theStyle.Material()->AlphaCutOff());
395 }
396
397 if (aPbrMat.EmissiveFactor != Graphic3d_Vec3 (0.0f, 0.0f, 0.0f))
398 {
399 myWriter->Key ("emissiveFactor");
400 myWriter->StartArray();
401 {
402 myWriter->Double (aPbrMat.EmissiveFactor.r());
403 myWriter->Double (aPbrMat.EmissiveFactor.g());
404 myWriter->Double (aPbrMat.EmissiveFactor.b());
405 }
406 myWriter->EndArray();
407 }
408 if (!aPbrMat.EmissiveTexture.IsNull()
409 && myImageMap.IsBound1 (aPbrMat.EmissiveTexture))
410 {
411 myWriter->Key ("emissiveTexture");
412 myWriter->StartObject();
413 {
414 myWriter->Key ("index");
415 const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.EmissiveTexture);
416 if (!anImageIdx.IsEmpty())
417 {
418 myWriter->Int (anImageIdx.IntegerValue());
419 }
420 }
421 myWriter->EndObject();
422 }
423
424 if (!aPbrMat.NormalTexture.IsNull()
425 && myImageMap.IsBound1 (aPbrMat.NormalTexture))
426 {
427 myWriter->Key ("normalTexture");
428 myWriter->StartObject();
429 {
430 myWriter->Key ("index");
431 const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.NormalTexture);
432 if (!anImageIdx.IsEmpty())
433 {
434 myWriter->Int (anImageIdx.IntegerValue());
435 }
436 }
437 myWriter->EndObject();
438 }
439
440 if (!aPbrMat.OcclusionTexture.IsNull()
441 && myImageMap.IsBound1 (aPbrMat.OcclusionTexture))
442 {
443 myWriter->Key ("occlusionTexture");
444 myWriter->StartObject();
445 {
446 myWriter->Key ("index");
447 const TCollection_AsciiString& anImageIdx = myImageMap.Find1 (aPbrMat.OcclusionTexture);
448 if (!anImageIdx.IsEmpty())
449 {
450 myWriter->Int (anImageIdx.IntegerValue());
451 }
452 }
453 myWriter->EndObject();
454 }
455 }
456 myWriter->EndObject();
457#else
458 (void )theStyle;
459 (void )theName;
460#endif
461}