Search code examples
javascriptthree.js3dmeshtexture-mapping

How to add env map onto gltf object


Im having quite a bit of trouble adding an environment map to a loaded GLTF / GLB file, as of now I get some sort of reflection instead of a black dot with a light point on it,

I was reading a bit of the document for three js and think I can pull it off with the standardmeshmaterial and applying it somehow to the object(gltf) and adding the mesh into the scene. I tried a similar mockup but the item disappears. I dont know how to go about it, help guys.

This is the environment map im trying to apply to it, (or something similar) https://hdrihaven.com/files/hdri_images/tonemapped/8192/venice_sunset.jpg

here is the codepen I am working on https://codepen.io/8AD/pen/XWpxmpO

HTML

<script src="https://unpkg.com/three@0.87.1/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/d9f87fb1a2c5db1ea0e2feda9bd42b39b5bedc41/build/three.min.js"></script>
<!-- OrbitControls.js -->
<script src="https://rawcdn.githack.com/mrdoob/three.js/d9f87fb1a2c5db1ea0e2feda9bd42b39b5bedc41/examples/js/controls/OrbitControls.js"></script>
<!-- DRACOLoader.js -->
<script src="https://rawcdn.githack.com/mrdoob/three.js/d9f87fb1a2c5db1ea0e2feda9bd42b39b5bedc41/examples/js/loaders/DRACOLoader.js"></script>
<!-- GLTFLoader.js -->
<script src="https://rawcdn.githack.com/mrdoob/three.js/d9f87fb1a2c5db1ea0e2feda9bd42b39b5bedc41/examples/js/loaders/GLTFLoader.js"></script>

<div id="3dmain">

  
</div>

JS

var gltf = null;
var mixer = null;
var clock = new THREE.Clock();
var controls;
var camera;
init();
animate();

var renderCalls = [];
function render () {
requestAnimationFrame( render );
renderCalls.forEach((callback)=>{ callback(); });
}
render();

  
function init() {
    width = window.innerWidth;
    height = window.innerHeight;
    
    scene = new THREE.Scene();
    
  var light = new THREE.PointLight( 0xffffcc, 20, 200 );
light.position.set( 4, 30, 80 );
scene.add( light );

var light2 = new THREE.AmbientLight( 0x20202A, 20, 100 );
light2.position.set( 30, -10, 30 );
scene.add( light2 );

  
    camera = new THREE.PerspectiveCamera( 60, width / height, 0.01, 10000 );
    camera.position.set(0, 3, 10);


    window.addEventListener( 'resize', function () {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize( window.innerWidth, window.innerHeight );
    }, false );
    
    var geometry = new THREE.BoxGeometry(100, 5, 100);
    var material = new THREE.MeshLambertMaterial({
        color: "#707070"
    });
    
 
    var manager = new THREE.LoadingManager();
    manager.onProgress = function ( item, loaded, total ) {
        console.log( item, loaded, total );
    };

    var loader = new THREE.GLTFLoader();
    loader.setCrossOrigin( 'anonymous' ); 
    
    
    var scale = 0.01;
    var url = "https://8ad.studio/wp-content/uploads/3D%20Assets/blimp.glb";
    
    loader.load(url, function (data) {
        gltf = data;
        var object = gltf.scene;
        object.scale.set(scale, scale, scale);
        //object.position.y = -5;
        //object.position.x = 4;
        object.castShadow = true;
        object.receiveShadow = true;

        var animations = gltf.animations;
        if ( animations && animations.length ) {
            mixer = new THREE.AnimationMixer( object );
            for ( var i = 0; i < animations.length; i ++ ) {
                var animation = animations[ i ];
                mixer.clipAction( animation ).play();
            }
        }
        scene.add(object);
    });

    

    renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true } );
    renderer.setClearColor( 0x000000, 0 );
    renderer.shadowMap.enabled = true;
    
    controls = new THREE.OrbitControls( camera,);
      controls.rotateSpeed = 0.3;
controls.zoomSpeed = 0.9;

controls.minDistance = 14;
controls.maxDistance = 14;

controls.minPolarAngle = 0; // radians
controls.maxPolarAngle = Math.PI /2; // radians

controls.enableDamping = true;
controls.dampingFactor = 0.05;

var renderCalls = [];
renderCalls.push(function(){
  controls.update()
});

    renderer.setSize( width, height );
    renderer.gammaOutput = true;
    document.getElementById('3dmain').appendChild( renderer.domElement );
}

function animate() {
    requestAnimationFrame( animate );
    if (mixer) mixer.update(clock.getDelta());
    controls.update();
    render();
}

function render() {
    renderer.render( scene, camera );
}



Solution

  • You have to include RGBELoader into your app for importing HDR textures and make use of PMREMGenerator in order to pre-process the environment map for the usage with a PBR material.

    var gltf = null;
    var mixer = null;
    var clock = new THREE.Clock();
    var controls;
    var camera;
    var renderer;
    init();
    animate();
    
    var renderCalls = [];
    
    function render() {
      requestAnimationFrame(render);
      renderCalls.forEach((callback) => {
        callback();
      });
    }
    render();
    
    
    function init() {
      width = window.innerWidth;
      height = window.innerHeight;
    
      scene = new THREE.Scene();
    
      var light = new THREE.PointLight(0xffffcc, 20, 200);
      light.position.set(4, 30, 80);
      scene.add(light);
    
      var light2 = new THREE.AmbientLight(0x20202A, 20, 100);
      light2.position.set(30, -10, 30);
      scene.add(light2);
    
      camera = new THREE.PerspectiveCamera(60, width / height, 0.01, 10000);
      camera.position.set(0, 3, 10);
    
    
      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      });
      renderer.outputEncoding = THREE.sRGBEncoding;
      renderer.toneMapping = THREE.ACESFilmicToneMapping;
      renderer.toneMappingExposure = 1;
      renderer.setClearColor(0x000000, 0);
      renderer.shadowMap.enabled = true;
    
      window.addEventListener('resize', function() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
      }, false);
    
      var geometry = new THREE.BoxGeometry(100, 5, 100);
      var material = new THREE.MeshLambertMaterial({
        color: "#707070"
      });
    
    
      var manager = new THREE.LoadingManager();
      manager.onProgress = function(item, loaded, total) {
        console.log(item, loaded, total);
      };
    
      var scale = 0.01;
      var url = "https://8ad.studio/wp-content/uploads/3D%20Assets/blimp.glb";
    
      var loader = new THREE.GLTFLoader();
      loader.setCrossOrigin('anonymous');
    
      const pmremGenerator = new THREE.PMREMGenerator(renderer);
      pmremGenerator.compileEquirectangularShader();
    
      const rgbeLoader = new THREE.RGBELoader();
      rgbeLoader.load('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr', function(texture) {
    
        const envMap = pmremGenerator.fromEquirectangular(texture).texture;
    
        scene.background = envMap;
        scene.environment = envMap;
    
        texture.dispose();
        pmremGenerator.dispose();
    
        loader.load(url, function(data) {
          gltf = data;
          var object = gltf.scene;
          object.scale.set(scale, scale, scale);
          //object.position.y = -5;
          //object.position.x = 4;
          object.castShadow = true;
          object.receiveShadow = true;
    
          var animations = gltf.animations;
          if (animations && animations.length) {
            mixer = new THREE.AnimationMixer(object);
            for (var i = 0; i < animations.length; i++) {
              var animation = animations[i];
              mixer.clipAction(animation).play();
            }
          }
          scene.add(object);
        });
    
      });
    
      controls = new THREE.OrbitControls(camera, renderer.domElement);
      controls.rotateSpeed = 0.3;
      controls.zoomSpeed = 0.9;
    
      controls.minDistance = 14;
      controls.maxDistance = 14;
    
      controls.minPolarAngle = 0; // radians
      controls.maxPolarAngle = Math.PI / 2; // radians
    
      controls.enableDamping = true;
      controls.dampingFactor = 0.05;
    
      var renderCalls = [];
      renderCalls.push(function() {
        controls.update()
      });
    
      renderer.setSize(width, height);
      document.getElementById('3dmain').appendChild(renderer.domElement);
    }
    
    function animate() {
      requestAnimationFrame(animate);
      if (mixer) mixer.update(clock.getDelta());
      controls.update();
      render();
    }
    
    function render() {
      renderer.render(scene, camera);
    }
    body {
          margin: 0;
    }
    <script src="https://cdn.jsdelivr.net/npm/three@0.127/build/three.js"></script>
    <!-- OrbitControls.js -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.127/examples/js/controls/OrbitControls.js"></script>
    <!-- DRACOLoader.js -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.127/examples/js/loaders/DRACOLoader.js"></script>
    <!-- GLTFLoader.js -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.127/examples/js/loaders/GLTFLoader.js"></script>
    <!-- RGBELoader.js -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.127/examples/js/loaders/RGBELoader.js"></script>
    
    <div id="3dmain">
    
    
    </div>

    The example applies the environment map to Scene.environment. However, you could also traverse through the glTF object and apply it to each material's envMap property.