From a60086c681dee7506b5f948839da4ee7a37b18a0 Mon Sep 17 00:00:00 2001
From: Sandro Weber <webers@in.tum.de>
Date: Wed, 16 Dec 2020 11:16:41 +0000
Subject: [PATCH] Merged in NUIT-221-collada-loader-1.4.1 (pull request #47)

[NUIT-221] mirroring frontend changes

* [NUIT-221] mirroring frontend changes

Approved-by: Stefano Nardo
Approved-by: Manos Angelidis
---
 gz3d/build/gz3d.js               | 275 +++++++++++++++++++++----------
 gz3d/src/gz3d-animated-models.js |  24 ++-
 gz3d/src/gzautoalignmodel.js     |   9 +-
 gz3d/src/gzbloomShader.js        |  35 ++--
 gz3d/src/gzcomposer.js           |  96 +++++------
 gz3d/src/gziface.js              |   2 +-
 gz3d/src/gzlabelmanager.js       |   2 +-
 gz3d/src/gzmanipulator.js        |   8 +-
 gz3d/src/gzmultiview.js          |   3 +-
 gz3d/src/gzscene.js              | 110 ++++++++++++-
 10 files changed, 379 insertions(+), 185 deletions(-)

diff --git a/gz3d/build/gz3d.js b/gz3d/build/gz3d.js
index b25f200..7d7f92a 100644
--- a/gz3d/build/gz3d.js
+++ b/gz3d/build/gz3d.js
@@ -207,13 +207,7 @@ GZ3D.AnimatedModel = function(scene) {
 };
 
 GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
-  this.loader = new THREE.ColladaLoader();
-  this.loader.textureLoadedCallback = () => {
-    this.scene.refresh3DViews();
-  };
-
   // Helper function to enable 'skinning' property so three.js treats meshes as deformable
-
   var enableSkinning = function(skinnedMesh) {
     var materials = skinnedMesh.material.materials;
     if (materials !== null && materials !== undefined) {
@@ -238,16 +232,18 @@ GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
   element.totalSize = 0;
   element.done = false;
   GZ3D.assetProgressData.assets.push(element);
-  var scene = this.scene;
-  this.loader.load(
+
+  this.scene.loadCollada(
     element.url,
-    function(collada) {
+    null,
+    null,
+    (dae) => {
       var modelParent = new THREE.Object3D();
       modelParent.name = modelName + '_animated';
       var linkParent = new THREE.Object3D();
 
       // Set gray, phong-shaded material for loaded model
-      collada.scene.traverse(function(child) {
+      dae.traverse(function(child) {
         if (child instanceof THREE.Mesh) {
           var applyDefaultMaterial = true;
 
@@ -273,13 +269,13 @@ GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
       });
 
       // Enable skinning for all child meshes
-      collada.scene.traverse(function(child) {
+      dae.traverse(function(child) {
         if (child instanceof THREE.SkinnedMesh) {
           enableSkinning(child);
         }
       });
 
-      linkParent.add(collada.scene);
+      linkParent.add(dae);
 
       // Hide model coordinate frames for the time being; remove as soon as position offset and rotation axis issues are fixed
       /*var collada_scene_axes = new THREE.AxisHelper(2);
@@ -316,13 +312,13 @@ GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
         return boneList;
       };
 
-      var boneList = getBoneList(collada.scene);
+      var boneList = getBoneList(dae);
       var boneHash = {};
       for (var k = 0; k < boneList.length; k++) {
         boneHash[boneList[k].name] = boneList[k];
       }
       // Skeleton visualization helper class
-      var helper = new THREE.SkeletonHelper(collada.scene);
+      var helper = new THREE.SkeletonHelper(dae);
 
       boneHash['Skeleton_Visual_Helper'] = helper;
       modelParent.userData = boneHash;
@@ -1019,8 +1015,10 @@ GZ3D.AutoAlignModel.prototype.alignToObjects = function(position) {
             snap2bbox.setFromObject(snap2obj);
             if (Math.abs(snap2bbox.min.x) !== Infinity) {
               if (i === 0) {
-                var s = bbox.getSize();
-                var s2 = snap2bbox.getSize();
+                var s = new THREE.Vector3();
+                bbox.getSize(s);
+                var s2 = new THREE.Vector3();
+                snap2bbox.getSize(s2);
                 if (
                   Math.abs(s.x - s2.x) > 0.01 ||
                   Math.abs(s.y - s2.y) > 0.01
@@ -1233,7 +1231,8 @@ GZ3D.AutoAlignModel.prototype.alignOnShape = function(position, hitDesc) {
         return;
       }
 
-      var q = hitDesc.object.getWorldQuaternion();
+      var q = new THREE.Quaternion();
+      hitDesc.object.getWorldQuaternion(q);
 
       var abv = new THREE.Vector3();
       var acv = new THREE.Vector3();
@@ -1738,7 +1737,8 @@ GZ3D.BloomShader.prototype = Object.assign(
       this.highPassUniforms['tDiffuse'].value = readBuffer.texture;
       this.highPassUniforms['luminosityThreshold'].value = this.threshold;
       this.quad.material = this.materialHighPassFilter;
-      renderer.render(this.scene, this.camera, this.renderTargetBright, true);
+      renderer.setRenderTarget(this.renderTargetBright);
+      renderer.render(this.scene, this.camera);
 
       // 2. Blur All the mips progressively
       var inputRenderTarget = this.renderTargetBright;
@@ -1752,12 +1752,9 @@ GZ3D.BloomShader.prototype = Object.assign(
         this.separableBlurMaterials[i].uniforms['direction'].value =
           GZ3D.BloomShader.BlurDirectionX;
 
-        renderer.render(
-          this.scene,
-          this.camera,
-          this.renderTargetsHorizontal[i],
-          true
-        );
+        renderer.clear();
+        renderer.setRenderTarget(this.renderTargetsHorizontal[i]);
+        renderer.render(this.scene, this.camera);
 
         this.separableBlurMaterials[i].uniforms[
           'colorTexture'
@@ -1766,12 +1763,9 @@ GZ3D.BloomShader.prototype = Object.assign(
         this.separableBlurMaterials[i].uniforms['direction'].value =
           GZ3D.BloomShader.BlurDirectionY;
 
-        renderer.render(
-          this.scene,
-          this.camera,
-          this.renderTargetsVertical[i],
-          true
-        );
+        renderer.clear();
+        renderer.setRenderTarget(this.renderTargetsVertical[i]);
+        renderer.render(this.scene, this.camera);
 
         inputRenderTarget = this.renderTargetsVertical[i];
       }
@@ -1783,12 +1777,9 @@ GZ3D.BloomShader.prototype = Object.assign(
       this.compositeMaterial.uniforms[
         'bloomTintColors'
       ].value = this.bloomTintColors;
-      renderer.render(
-        this.scene,
-        this.camera,
-        this.renderTargetsHorizontal[0],
-        true
-      );
+      renderer.clear();
+      renderer.setRenderTarget(this.renderTargetsHorizontal[0]);
+      renderer.render(this.scene, this.camera);
 
       // Blend it additively over the input texture
       this.quad.material = this.materialCopy;
@@ -1799,8 +1790,9 @@ GZ3D.BloomShader.prototype = Object.assign(
       if (maskActive) {
         renderer.context.enable(renderer.context.STENCIL_TEST);
       }
-
-      renderer.render(this.scene, this.camera, readBuffer, false);
+      
+      renderer.setRenderTarget(readBuffer);
+      renderer.render(this.scene, this.camera);
 
       renderer.setClearColor(this.oldClearColor, this.oldClearAlpha);
       renderer.autoClear = oldAutoClear;
@@ -2885,7 +2877,9 @@ GZ3D.Composer.prototype.render = function(view) {
       this.scene.background = null; // Some effects should be disabled during depth buffer rendering
       this.lensFlare.visible = false;
       this.scene.overrideMaterial = view.depthMaterial;
-      view.renderer.render(this.scene, camera, view.depthRenderTarget, true); // Render to depth buffer now!
+      view.renderer.clear();
+      view.renderer.setRenderTarget(view.depthRenderTarget);
+      view.renderer.render(this.scene, camera); // Render to depth buffer now!
       this.scene.overrideMaterial = null;
     }
 
@@ -3121,50 +3115,53 @@ GZ3D.Composer.prototype.buildSkin = function(skin) {
     skin.initialized = true;
     var parent = that.scene.getObjectByName(skin.parentObject, true);
     if (parent) {
-      var loader = new THREE.ColladaLoader();
+      var uri = GZ3D.assetsPath + '/' + skin.mesh;
+      that.gz3dScene.loadCollada(
+        uri, 
+        null, 
+        null, 
+        (dae) => {
+          var mapToMesh = that.scene.getObjectByName(skin.mapTo);
 
-      loader.load(GZ3D.assetsPath + '/' + skin.mesh, function(collada) {
-        var dae = collada.scene;
-        var mapToMesh = that.scene.getObjectByName(skin.mapTo);
+          if (skin.scale)
+            dae.scale.copy(new THREE.Vector3(skin.scale, skin.scale, skin.scale));
 
-        if (skin.scale)
-          dae.scale.copy(new THREE.Vector3(skin.scale, skin.scale, skin.scale));
-
-        parent.add(dae);
-        that.gz3dScene.refresh3DViews();
+          parent.add(dae);
+          that.gz3dScene.refresh3DViews();
 
-        dae.traverse(function(object) {
-          object._isPartOfTheSkin = true;
-        });
+          dae.traverse(function(object) {
+            object._isPartOfTheSkin = true;
+          });
 
-        var skinBoneMap = [];
-        var skinnedObject = {
-          skinBoneMap: skinBoneMap,
-          definition: skin,
-          skinMesh: dae,
-          mapToMesh: mapToMesh,
-          parentMesh: parent
-        };
+          var skinBoneMap = [];
+          var skinnedObject = {
+            skinBoneMap: skinBoneMap,
+            definition: skin,
+            skinMesh: dae,
+            mapToMesh: mapToMesh,
+            parentMesh: parent
+          };
 
-        that.skinnedObjects.push(skinnedObject);
+          that.skinnedObjects.push(skinnedObject);
 
-        dae._skinnedObject = skinnedObject;
-        parent._skinnedObject = skinnedObject;
-        mapToMesh._skinnedObject = skinnedObject;
+          dae._skinnedObject = skinnedObject;
+          parent._skinnedObject = skinnedObject;
+          mapToMesh._skinnedObject = skinnedObject;
 
-        dae.traverse(function(bone) {
-          if (bone instanceof THREE.Bone) {
-            var r = mapToMesh.getObjectByName(skin.bonePrefix + bone.name);
-            if (r) {
-              skinBoneMap.push({ joint: r, bone: bone });
-              that.setSkinVisibility(skinnedObject, skin.visible);
+          dae.traverse(function(bone) {
+            if (bone instanceof THREE.Bone) {
+              var r = mapToMesh.getObjectByName(skin.bonePrefix + bone.name);
+              if (r) {
+                skinBoneMap.push({ joint: r, bone: bone });
+                that.setSkinVisibility(skinnedObject, skin.visible);
 
-              r._skinnedObject = skinnedObject;
-              bone._skinnedObject = skinnedObject;
+                r._skinnedObject = skinnedObject;
+                bone._skinnedObject = skinnedObject;
+              }
             }
-          }
-        });
-      });
+          });
+        }
+      );
     }
   }
 };
@@ -3181,11 +3178,9 @@ GZ3D.Composer.prototype.buildSkins = function() {
   if (!this.skinnedObjects) this.skinnedObjects = [];
 
   // Skins created from the .ini file of the experiment
-
   if (cs.skins) cs.skins.forEach(skin => that.buildSkin(skin));
 
   // Skins created dynamically from the frontend
-
   if (this.skins) this.skins.forEach(skin => that.buildSkin(skin));
 
   this.skinsInitialized = true;
@@ -3212,7 +3207,8 @@ GZ3D.Composer.prototype.updateSkin = function() {
       var invM = new THREE.Matrix4();
       invM.getInverse(bone.parent.matrixWorld);
 
-      var p = joint.getWorldPosition();
+      var p = new THREE.Vector3();
+      joint.getWorldPosition(p);
 
       var jM = new THREE.Matrix4();
       var bp = new THREE.Vector3(),
@@ -5979,7 +5975,7 @@ GZ3D.GZIface.prototype.createGeom = function(
 
           // HBP Change (Luc): we assume that all requested collada files are
           // are web-compliant
-          if (modelUri.indexOf('.dae') !== -1 || modelUri.indexOf('.DAE') !== -1) {
+          if (modelUri.substr(-4).toLowerCase() === '.dae') {
             var materialName = parent.name + '::' + element.url;
 
             that.scene.loadMesh(
@@ -6817,7 +6813,7 @@ GZ3D.LabelManager.prototype.createLineLabel = function(parent) {
     linewidth: 3
   });
   var line = new THREE.Line(lineGeometry, lineMaterial);
-  lineGeometry.computeLineDistances();
+  line.computeLineDistances();
 
   this.scene.scene.add(line);
 
@@ -8362,9 +8358,13 @@ GZ3D.Manipulator = function(gz3dScene, mobile) {
           }
         };
 
+        let worldPose = new THREE.Vector3();
+        let worldRotation = new THREE.Quaternion();
+        currentObject.getWorldPosition(worldPose);
+        currentObject.getWorldQuaternion(worldRotation);
         var objectWorldPose = {
-          pos: currentObject.getWorldPosition(),
-          rot: currentObject.getWorldQuaternion()
+          pos: worldPose,
+          rot: worldRotation
         };
 
         var mouseDistance = getMouseMoveDistance(
@@ -9022,7 +9022,8 @@ GZ3D.MultiView.prototype.setShadowMaps = function(enabled) {
 
 GZ3D.MultiView.prototype.clearRenderTargets = function(target) {
   this.views.forEach(function(view, index, array) {
-    view.renderer.clearTarget(target);
+    view.renderer.setRenderTarget(target);
+    view.renderer.clear();
   });
 };
 
@@ -10385,6 +10386,7 @@ GZ3D.Scene.prototype.setPose = function(model, position, orientation) {
   model.quaternion.x = orientation.x;
   model.quaternion.y = orientation.y;
   model.quaternion.z = orientation.z;
+
   this.refresh3DViews();
   this.updateBoundingBox(model);
 };
@@ -11221,6 +11223,101 @@ GZ3D.Scene.prototype.loadMesh = function(
   }
 };
 
+GZ3D.Scene.prototype.preparePBRMaterials = function(basePath, collada) {
+  var libEffects = collada.library.effects;
+  var libMaterials = collada.library.materials;
+  var libImages = collada.library.images;
+
+  for (const materialKey in libMaterials) {
+    var material = libMaterials[materialKey];
+    var effect = libEffects[material.url];
+
+    function getTexturePath(textureObject) {
+      var sampler = effect.profile.samplers[textureObject.id];
+      var surface = effect.profile.surfaces[sampler.source];
+
+      if (sampler !== undefined && surface !== null) {
+        var img = libImages[surface.init_from];
+
+        return basePath + '/' + img.build;
+      }
+    }
+
+    var parameters = effect.profile.technique.parameters;
+    var parameter;
+    var pbrMaterial = null;
+
+    var pbrKeyToThreeJSMap = {
+      Base_Color: 'map',
+      Metallic: 'metalnessMap',
+      Roughness: 'roughnessMap',
+      Mixed_AO: 'aoMap',
+      Emissive: 'emissiveMap',
+      Normal: 'normalMap',
+      Height: 'displacementMap'
+    };
+
+    for (var key in parameters) {
+      parameter = parameters[key];
+      if (parameter.texture) {
+        var texturePath = getTexturePath(parameter.texture);
+
+        if (
+          texturePath &&
+          (texturePath.indexOf('PBR_') >= 0 ||
+            texturePath.indexOf('PBRFULL_') >= 0)
+        ) {
+          for (var k in pbrKeyToThreeJSMap) {
+            if (texturePath.indexOf(k) >= 0) {
+              if (pbrMaterial === null) {
+                pbrMaterial = {};
+              }
+
+              pbrMaterial[pbrKeyToThreeJSMap[k]] = texturePath;
+
+              if (
+                texturePath.indexOf('PBRFULL_') >= 0 &&
+                k === 'Base_Color'
+              ) {
+                // If the prefix is PBRFULL it means that all the PBR textures are present
+                // but that only the basic color map have been linked to the dae.
+
+                var allpbrkeywords = [
+                  'Metallic',
+                  'Mixed_AO',
+                  'Roughness',
+                  'Normal',
+                  'Roughness'
+                ];
+
+                for (var pbri in allpbrkeywords) {
+                  var pbrk = allpbrkeywords[pbri];
+                  var path = texturePath;
+
+                  path = path.replace('Base_Color', pbrk);
+                  if (pbrk === 'Normal') {
+                    // Normal map must be png. In case the Base_Color is a jpg,
+                    // change extension to png
+
+                    path = path.replace('.jpg', '.png');
+                    path = path.replace('.jpeg', '.png');
+                  }
+
+                  pbrMaterial[pbrKeyToThreeJSMap[pbrk]] = path;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (pbrMaterial !== null) {
+      material.build.pbrMaterialDescription = pbrMaterial; // If PBR material has been found, store it for future usage
+    }
+  }
+}
+
 /**
  * Load collada file
  * @param {string} uri
@@ -11236,7 +11333,6 @@ GZ3D.Scene.prototype.loadCollada = function(
   progressCallback
 ) {
   var dae;
-  var mesh = null;
 
   var cachedModel = this.cachedModels[uri];
   if (cachedModel && cachedModel.referenceObject) {
@@ -11250,12 +11346,8 @@ GZ3D.Scene.prototype.loadCollada = function(
   loader.textureLoadedCallback = () => {
     this.refresh3DViews();
   };
-
-  // var loader = new ColladaLoader2();
-  // loader.options.convertUpAxis = true;
-  var thatURI = uri;
+  var basePath = uri.substring(0, uri.lastIndexOf('/'));
   var thatSubmesh = submesh;
-  var thatCenterSubmesh = centerSubmesh;
 
   var that = this;
   loader.load(
@@ -11270,8 +11362,13 @@ GZ3D.Scene.prototype.loadCollada = function(
       dae = collada.scene;
       dae.updateMatrix();
       that.prepareColladaMesh(dae);
-      dae = dae.clone();
       that.useColladaSubMesh(dae, thatSubmesh, centerSubmesh);
+      that.preparePBRMaterials(basePath, collada);
+
+      // updating ColladaLoader to be able to load model specs v1.4.1 introduced a change in rotations
+      // this compensates for the difference in rotation
+      // automatic conversion of up-axis as claimed by ColladaLoader doesn't seem to work in our case
+      dae.quaternion.premultiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI / 2));
 
       dae.name = uri;
       callback(dae);
diff --git a/gz3d/src/gz3d-animated-models.js b/gz3d/src/gz3d-animated-models.js
index 20c5870..4259859 100644
--- a/gz3d/src/gz3d-animated-models.js
+++ b/gz3d/src/gz3d-animated-models.js
@@ -4,13 +4,7 @@ GZ3D.AnimatedModel = function(scene) {
 };
 
 GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
-  this.loader = new THREE.ColladaLoader();
-  this.loader.textureLoadedCallback = () => {
-    this.scene.refresh3DViews();
-  };
-
   // Helper function to enable 'skinning' property so three.js treats meshes as deformable
-
   var enableSkinning = function(skinnedMesh) {
     var materials = skinnedMesh.material.materials;
     if (materials !== null && materials !== undefined) {
@@ -35,16 +29,18 @@ GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
   element.totalSize = 0;
   element.done = false;
   GZ3D.assetProgressData.assets.push(element);
-  var scene = this.scene;
-  this.loader.load(
+
+  this.scene.loadCollada(
     element.url,
-    function(collada) {
+    null,
+    null,
+    (dae) => {
       var modelParent = new THREE.Object3D();
       modelParent.name = modelName + '_animated';
       var linkParent = new THREE.Object3D();
 
       // Set gray, phong-shaded material for loaded model
-      collada.scene.traverse(function(child) {
+      dae.traverse(function(child) {
         if (child instanceof THREE.Mesh) {
           var applyDefaultMaterial = true;
 
@@ -70,13 +66,13 @@ GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
       });
 
       // Enable skinning for all child meshes
-      collada.scene.traverse(function(child) {
+      dae.traverse(function(child) {
         if (child instanceof THREE.SkinnedMesh) {
           enableSkinning(child);
         }
       });
 
-      linkParent.add(collada.scene);
+      linkParent.add(dae);
 
       // Hide model coordinate frames for the time being; remove as soon as position offset and rotation axis issues are fixed
       /*var collada_scene_axes = new THREE.AxisHelper(2);
@@ -113,13 +109,13 @@ GZ3D.AnimatedModel.prototype.loadAnimatedModel = function(modelName) {
         return boneList;
       };
 
-      var boneList = getBoneList(collada.scene);
+      var boneList = getBoneList(dae);
       var boneHash = {};
       for (var k = 0; k < boneList.length; k++) {
         boneHash[boneList[k].name] = boneList[k];
       }
       // Skeleton visualization helper class
-      var helper = new THREE.SkeletonHelper(collada.scene);
+      var helper = new THREE.SkeletonHelper(dae);
 
       boneHash['Skeleton_Visual_Helper'] = helper;
       modelParent.userData = boneHash;
diff --git a/gz3d/src/gzautoalignmodel.js b/gz3d/src/gzautoalignmodel.js
index afbb98f..2344d31 100644
--- a/gz3d/src/gzautoalignmodel.js
+++ b/gz3d/src/gzautoalignmodel.js
@@ -439,8 +439,10 @@ GZ3D.AutoAlignModel.prototype.alignToObjects = function(position) {
             snap2bbox.setFromObject(snap2obj);
             if (Math.abs(snap2bbox.min.x) !== Infinity) {
               if (i === 0) {
-                var s = bbox.getSize();
-                var s2 = snap2bbox.getSize();
+                var s = new THREE.Vector3();
+                bbox.getSize(s);
+                var s2 = new THREE.Vector3();
+                snap2bbox.getSize(s2);
                 if (
                   Math.abs(s.x - s2.x) > 0.01 ||
                   Math.abs(s.y - s2.y) > 0.01
@@ -653,7 +655,8 @@ GZ3D.AutoAlignModel.prototype.alignOnShape = function(position, hitDesc) {
         return;
       }
 
-      var q = hitDesc.object.getWorldQuaternion();
+      var q = new THREE.Quaternion();
+      hitDesc.object.getWorldQuaternion(q);
 
       var abv = new THREE.Vector3();
       var acv = new THREE.Vector3();
diff --git a/gz3d/src/gzbloomShader.js b/gz3d/src/gzbloomShader.js
index a83d450..adccff1 100644
--- a/gz3d/src/gzbloomShader.js
+++ b/gz3d/src/gzbloomShader.js
@@ -204,7 +204,8 @@ GZ3D.BloomShader.prototype = Object.assign(
       this.highPassUniforms['tDiffuse'].value = readBuffer.texture;
       this.highPassUniforms['luminosityThreshold'].value = this.threshold;
       this.quad.material = this.materialHighPassFilter;
-      renderer.render(this.scene, this.camera, this.renderTargetBright, true);
+      renderer.setRenderTarget(this.renderTargetBright);
+      renderer.render(this.scene, this.camera);
 
       // 2. Blur All the mips progressively
       var inputRenderTarget = this.renderTargetBright;
@@ -218,12 +219,9 @@ GZ3D.BloomShader.prototype = Object.assign(
         this.separableBlurMaterials[i].uniforms['direction'].value =
           GZ3D.BloomShader.BlurDirectionX;
 
-        renderer.render(
-          this.scene,
-          this.camera,
-          this.renderTargetsHorizontal[i],
-          true
-        );
+        renderer.clear();
+        renderer.setRenderTarget(this.renderTargetsHorizontal[i]);
+        renderer.render(this.scene, this.camera);
 
         this.separableBlurMaterials[i].uniforms[
           'colorTexture'
@@ -232,12 +230,9 @@ GZ3D.BloomShader.prototype = Object.assign(
         this.separableBlurMaterials[i].uniforms['direction'].value =
           GZ3D.BloomShader.BlurDirectionY;
 
-        renderer.render(
-          this.scene,
-          this.camera,
-          this.renderTargetsVertical[i],
-          true
-        );
+        renderer.clear();
+        renderer.setRenderTarget(this.renderTargetsVertical[i]);
+        renderer.render(this.scene, this.camera);
 
         inputRenderTarget = this.renderTargetsVertical[i];
       }
@@ -249,12 +244,9 @@ GZ3D.BloomShader.prototype = Object.assign(
       this.compositeMaterial.uniforms[
         'bloomTintColors'
       ].value = this.bloomTintColors;
-      renderer.render(
-        this.scene,
-        this.camera,
-        this.renderTargetsHorizontal[0],
-        true
-      );
+      renderer.clear();
+      renderer.setRenderTarget(this.renderTargetsHorizontal[0]);
+      renderer.render(this.scene, this.camera);
 
       // Blend it additively over the input texture
       this.quad.material = this.materialCopy;
@@ -265,8 +257,9 @@ GZ3D.BloomShader.prototype = Object.assign(
       if (maskActive) {
         renderer.context.enable(renderer.context.STENCIL_TEST);
       }
-
-      renderer.render(this.scene, this.camera, readBuffer, false);
+      
+      renderer.setRenderTarget(readBuffer);
+      renderer.render(this.scene, this.camera);
 
       renderer.setClearColor(this.oldClearColor, this.oldClearAlpha);
       renderer.autoClear = oldAutoClear;
diff --git a/gz3d/src/gzcomposer.js b/gz3d/src/gzcomposer.js
index a5bb2c3..c61c602 100644
--- a/gz3d/src/gzcomposer.js
+++ b/gz3d/src/gzcomposer.js
@@ -965,7 +965,9 @@ GZ3D.Composer.prototype.render = function(view) {
       this.scene.background = null; // Some effects should be disabled during depth buffer rendering
       this.lensFlare.visible = false;
       this.scene.overrideMaterial = view.depthMaterial;
-      view.renderer.render(this.scene, camera, view.depthRenderTarget, true); // Render to depth buffer now!
+      view.renderer.clear();
+      view.renderer.setRenderTarget(view.depthRenderTarget);
+      view.renderer.render(this.scene, camera); // Render to depth buffer now!
       this.scene.overrideMaterial = null;
     }
 
@@ -1201,50 +1203,53 @@ GZ3D.Composer.prototype.buildSkin = function(skin) {
     skin.initialized = true;
     var parent = that.scene.getObjectByName(skin.parentObject, true);
     if (parent) {
-      var loader = new THREE.ColladaLoader();
-
-      loader.load(GZ3D.assetsPath + '/' + skin.mesh, function(collada) {
-        var dae = collada.scene;
-        var mapToMesh = that.scene.getObjectByName(skin.mapTo);
-
-        if (skin.scale)
-          dae.scale.copy(new THREE.Vector3(skin.scale, skin.scale, skin.scale));
-
-        parent.add(dae);
-        that.gz3dScene.refresh3DViews();
-
-        dae.traverse(function(object) {
-          object._isPartOfTheSkin = true;
-        });
-
-        var skinBoneMap = [];
-        var skinnedObject = {
-          skinBoneMap: skinBoneMap,
-          definition: skin,
-          skinMesh: dae,
-          mapToMesh: mapToMesh,
-          parentMesh: parent
-        };
-
-        that.skinnedObjects.push(skinnedObject);
-
-        dae._skinnedObject = skinnedObject;
-        parent._skinnedObject = skinnedObject;
-        mapToMesh._skinnedObject = skinnedObject;
-
-        dae.traverse(function(bone) {
-          if (bone instanceof THREE.Bone) {
-            var r = mapToMesh.getObjectByName(skin.bonePrefix + bone.name);
-            if (r) {
-              skinBoneMap.push({ joint: r, bone: bone });
-              that.setSkinVisibility(skinnedObject, skin.visible);
+      var uri = GZ3D.assetsPath + '/' + skin.mesh;
+      that.gz3dScene.loadCollada(
+        uri, 
+        null, 
+        null, 
+        (dae) => {
+          var mapToMesh = that.scene.getObjectByName(skin.mapTo);
+
+          if (skin.scale)
+            dae.scale.copy(new THREE.Vector3(skin.scale, skin.scale, skin.scale));
+
+          parent.add(dae);
+          that.gz3dScene.refresh3DViews();
 
-              r._skinnedObject = skinnedObject;
-              bone._skinnedObject = skinnedObject;
+          dae.traverse(function(object) {
+            object._isPartOfTheSkin = true;
+          });
+
+          var skinBoneMap = [];
+          var skinnedObject = {
+            skinBoneMap: skinBoneMap,
+            definition: skin,
+            skinMesh: dae,
+            mapToMesh: mapToMesh,
+            parentMesh: parent
+          };
+
+          that.skinnedObjects.push(skinnedObject);
+
+          dae._skinnedObject = skinnedObject;
+          parent._skinnedObject = skinnedObject;
+          mapToMesh._skinnedObject = skinnedObject;
+
+          dae.traverse(function(bone) {
+            if (bone instanceof THREE.Bone) {
+              var r = mapToMesh.getObjectByName(skin.bonePrefix + bone.name);
+              if (r) {
+                skinBoneMap.push({ joint: r, bone: bone });
+                that.setSkinVisibility(skinnedObject, skin.visible);
+
+                r._skinnedObject = skinnedObject;
+                bone._skinnedObject = skinnedObject;
+              }
             }
-          }
-        });
-      });
+          });
+        }
+      );
     }
   }
 };
@@ -1261,11 +1266,9 @@ GZ3D.Composer.prototype.buildSkins = function() {
   if (!this.skinnedObjects) this.skinnedObjects = [];
 
   // Skins created from the .ini file of the experiment
-
   if (cs.skins) cs.skins.forEach(skin => that.buildSkin(skin));
 
   // Skins created dynamically from the frontend
-
   if (this.skins) this.skins.forEach(skin => that.buildSkin(skin));
 
   this.skinsInitialized = true;
@@ -1292,7 +1295,8 @@ GZ3D.Composer.prototype.updateSkin = function() {
       var invM = new THREE.Matrix4();
       invM.getInverse(bone.parent.matrixWorld);
 
-      var p = joint.getWorldPosition();
+      var p = new THREE.Vector3();
+      joint.getWorldPosition(p);
 
       var jM = new THREE.Matrix4();
       var bp = new THREE.Vector3(),
diff --git a/gz3d/src/gziface.js b/gz3d/src/gziface.js
index 47707a5..f28470d 100644
--- a/gz3d/src/gziface.js
+++ b/gz3d/src/gziface.js
@@ -1465,7 +1465,7 @@ GZ3D.GZIface.prototype.createGeom = function(
 
           // HBP Change (Luc): we assume that all requested collada files are
           // are web-compliant
-          if (modelUri.indexOf('.dae') !== -1 || modelUri.indexOf('.DAE') !== -1) {
+          if (modelUri.substr(-4).toLowerCase() === '.dae') {
             var materialName = parent.name + '::' + element.url;
 
             that.scene.loadMesh(
diff --git a/gz3d/src/gzlabelmanager.js b/gz3d/src/gzlabelmanager.js
index 7647921..d4eb3e4 100644
--- a/gz3d/src/gzlabelmanager.js
+++ b/gz3d/src/gzlabelmanager.js
@@ -288,7 +288,7 @@ GZ3D.LabelManager.prototype.createLineLabel = function(parent) {
     linewidth: 3
   });
   var line = new THREE.Line(lineGeometry, lineMaterial);
-  lineGeometry.computeLineDistances();
+  line.computeLineDistances();
 
   this.scene.scene.add(line);
 
diff --git a/gz3d/src/gzmanipulator.js b/gz3d/src/gzmanipulator.js
index fc1088f..afc47d4 100644
--- a/gz3d/src/gzmanipulator.js
+++ b/gz3d/src/gzmanipulator.js
@@ -1360,9 +1360,13 @@ GZ3D.Manipulator = function(gz3dScene, mobile) {
           }
         };
 
+        let worldPose = new THREE.Vector3();
+        let worldRotation = new THREE.Quaternion();
+        currentObject.getWorldPosition(worldPose);
+        currentObject.getWorldQuaternion(worldRotation);
         var objectWorldPose = {
-          pos: currentObject.getWorldPosition(),
-          rot: currentObject.getWorldQuaternion()
+          pos: worldPose,
+          rot: worldRotation
         };
 
         var mouseDistance = getMouseMoveDistance(
diff --git a/gz3d/src/gzmultiview.js b/gz3d/src/gzmultiview.js
index a47d8b4..6ed99d2 100644
--- a/gz3d/src/gzmultiview.js
+++ b/gz3d/src/gzmultiview.js
@@ -370,6 +370,7 @@ GZ3D.MultiView.prototype.setShadowMaps = function(enabled) {
 
 GZ3D.MultiView.prototype.clearRenderTargets = function(target) {
   this.views.forEach(function(view, index, array) {
-    view.renderer.clearTarget(target);
+    view.renderer.setRenderTarget(target);
+    view.renderer.clear();
   });
 };
diff --git a/gz3d/src/gzscene.js b/gz3d/src/gzscene.js
index dff1dc7..492f1db 100644
--- a/gz3d/src/gzscene.js
+++ b/gz3d/src/gzscene.js
@@ -877,6 +877,7 @@ GZ3D.Scene.prototype.setPose = function(model, position, orientation) {
   model.quaternion.x = orientation.x;
   model.quaternion.y = orientation.y;
   model.quaternion.z = orientation.z;
+
   this.refresh3DViews();
   this.updateBoundingBox(model);
 };
@@ -1713,6 +1714,101 @@ GZ3D.Scene.prototype.loadMesh = function(
   }
 };
 
+GZ3D.Scene.prototype.preparePBRMaterials = function(basePath, collada) {
+  var libEffects = collada.library.effects;
+  var libMaterials = collada.library.materials;
+  var libImages = collada.library.images;
+
+  for (const materialKey in libMaterials) {
+    var material = libMaterials[materialKey];
+    var effect = libEffects[material.url];
+
+    function getTexturePath(textureObject) {
+      var sampler = effect.profile.samplers[textureObject.id];
+      var surface = effect.profile.surfaces[sampler.source];
+
+      if (sampler !== undefined && surface !== null) {
+        var img = libImages[surface.init_from];
+
+        return basePath + '/' + img.build;
+      }
+    }
+
+    var parameters = effect.profile.technique.parameters;
+    var parameter;
+    var pbrMaterial = null;
+
+    var pbrKeyToThreeJSMap = {
+      Base_Color: 'map',
+      Metallic: 'metalnessMap',
+      Roughness: 'roughnessMap',
+      Mixed_AO: 'aoMap',
+      Emissive: 'emissiveMap',
+      Normal: 'normalMap',
+      Height: 'displacementMap'
+    };
+
+    for (var key in parameters) {
+      parameter = parameters[key];
+      if (parameter.texture) {
+        var texturePath = getTexturePath(parameter.texture);
+
+        if (
+          texturePath &&
+          (texturePath.indexOf('PBR_') >= 0 ||
+            texturePath.indexOf('PBRFULL_') >= 0)
+        ) {
+          for (var k in pbrKeyToThreeJSMap) {
+            if (texturePath.indexOf(k) >= 0) {
+              if (pbrMaterial === null) {
+                pbrMaterial = {};
+              }
+
+              pbrMaterial[pbrKeyToThreeJSMap[k]] = texturePath;
+
+              if (
+                texturePath.indexOf('PBRFULL_') >= 0 &&
+                k === 'Base_Color'
+              ) {
+                // If the prefix is PBRFULL it means that all the PBR textures are present
+                // but that only the basic color map have been linked to the dae.
+
+                var allpbrkeywords = [
+                  'Metallic',
+                  'Mixed_AO',
+                  'Roughness',
+                  'Normal',
+                  'Roughness'
+                ];
+
+                for (var pbri in allpbrkeywords) {
+                  var pbrk = allpbrkeywords[pbri];
+                  var path = texturePath;
+
+                  path = path.replace('Base_Color', pbrk);
+                  if (pbrk === 'Normal') {
+                    // Normal map must be png. In case the Base_Color is a jpg,
+                    // change extension to png
+
+                    path = path.replace('.jpg', '.png');
+                    path = path.replace('.jpeg', '.png');
+                  }
+
+                  pbrMaterial[pbrKeyToThreeJSMap[pbrk]] = path;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (pbrMaterial !== null) {
+      material.build.pbrMaterialDescription = pbrMaterial; // If PBR material has been found, store it for future usage
+    }
+  }
+}
+
 /**
  * Load collada file
  * @param {string} uri
@@ -1728,7 +1824,6 @@ GZ3D.Scene.prototype.loadCollada = function(
   progressCallback
 ) {
   var dae;
-  var mesh = null;
 
   var cachedModel = this.cachedModels[uri];
   if (cachedModel && cachedModel.referenceObject) {
@@ -1742,12 +1837,8 @@ GZ3D.Scene.prototype.loadCollada = function(
   loader.textureLoadedCallback = () => {
     this.refresh3DViews();
   };
-
-  // var loader = new ColladaLoader2();
-  // loader.options.convertUpAxis = true;
-  var thatURI = uri;
+  var basePath = uri.substring(0, uri.lastIndexOf('/'));
   var thatSubmesh = submesh;
-  var thatCenterSubmesh = centerSubmesh;
 
   var that = this;
   loader.load(
@@ -1762,8 +1853,13 @@ GZ3D.Scene.prototype.loadCollada = function(
       dae = collada.scene;
       dae.updateMatrix();
       that.prepareColladaMesh(dae);
-      dae = dae.clone();
       that.useColladaSubMesh(dae, thatSubmesh, centerSubmesh);
+      that.preparePBRMaterials(basePath, collada);
+
+      // updating ColladaLoader to be able to load model specs v1.4.1 introduced a change in rotations
+      // this compensates for the difference in rotation
+      // automatic conversion of up-axis as claimed by ColladaLoader doesn't seem to work in our case
+      dae.quaternion.premultiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI / 2));
 
       dae.name = uri;
       callback(dae);
-- 
GitLab