A step-by-step guide on incorporating an environment map onto a gltf object

I am struggling to add an environment map to a loaded GLTF/GLB file. Currently, I am getting a reflection instead of the desired effect where there should be a black dot with a light point on it.

After reading some of the documentation for Three.js, I believe I can achieve this by using StandardMeshMaterial and applying it to the object (GLTF) before adding the mesh into the scene. However, my attempts so far have resulted in the item disappearing. I'm not sure how to proceed, any help would be appreciated.

Here is the link to the environment map I am trying to apply:

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

HTML

<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="74001c06111134445a4c435a45">[email protected]</a>/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 );
}

Answer №1

To import HDR textures into your app, you must include RGBELoader and utilize PMREMGenerator to preprocess the environment map for PBR material usage.

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.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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="daaeb2a8bfbf9aeaf4ebe8ed">[email protected]</a>/build/three.js"></script>
<!-- OrbitControls.js -->
<script src="https://cdn.jsdelivr.netnpm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3d49555f484817575944496">[email protected]</a>/examples/js/controls/OrbitControls.js"></script>
<!-- DRACOLoader.js -->
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8ffbe7fdeaeacfbfa1bebdb8">[email protected]</a>/examples/js/loaders/DRACOLoader.js"></script>
<!-- GLTFLoader.js -->
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e2968a908787a2d2ccd3d0d5">[email protected]</a>/examples/js/loaders/GLTFLoader.js"></script>
<!-- RGBELoader.js -->
<script src="https://cdn.jsdelivr.netnpm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5d29252f38381d6d736c6f6a">[email protected]</a>/examples/js/loaders/RGBELoader.js"></script>

<div id="3dmain">


</div>

In this scenario, the environment map is added to Scene.environment. It's also possible to go through the glTF object and assign it to each material's envMap property.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to load JSON model texture

I successfully transformed an obj file into a json model using a Python tool, and now I am attempting to load it into my project. Below is the code snippet: var camera, scene, renderer; var mesh, aircraft; function addModelToScene( geometry, materials ) ...

Combining inheritance and isolated scopes: a comprehensive guide

I've encountered a situation where I need to sort an HTML table. Here is the code snippet: <table> <thead> <tr> <th custom-sort-one order="'Name'" >Name</th> </ ...

Manipulating Objects in Three.js: Adding and Removing Children from Rotated Entities

In my attempt to create a virtual Rubik's cube simulation, I decided to randomly select a face and rotate it. To accomplish this, I created 27 cube meshes and positioned them accordingly. You can view the Rubik's cube in action, albeit erraticall ...

Lottie-web experiences a memory leak

Currently implementing lottie web on my front-end, but encountering persistent memory leaks. The JavaScript VM instance remains below 10MB when lottie is removed altogether. However, upon enabling lottie, the memory usage escalates rapidly whenever the pa ...

Guide on how to initiate a file download with text area content by clicking an HTML button

I came across this code snippet on GeeksforGeeks, and it partially solves an issue I was facing. <script> function download(file, text) { //creating an invisible element var element = document.createElement('a'); ...

What could be the reason for ng-init failing to activate the $watch listener?

When I run the code in my application, there are instances where ng-init fails to trigger the $watch function. Any suggestions on how to fix this? HTML <div ng-controller="MyCtrl"> <p ng-init="stages = 'coco'">{{x}}</p> < ...

Tips for customizing the appearance of popup windows

I want to enhance the appearance of my popup window by applying a different format for opening it. How can I style it so that it looks visually appealing when the popup window opens? You can find below the source code I am working with: HTML: <div onM ...

Invoke index functions within a component

I have a widget/component written in Angular 4 within the index.html file. Before and after this angular app, there are various HTML elements due to the nature of it being an additional component for the website. The head section of the index file include ...

The variable 'X' in Node.js is not been declared

I've been struggling with this problem, trying to fetch my most recent tweets as an array using the npm module https://github.com/noffle/latest-tweets. However, no matter how I approach it, I always encounter errors such as 'posts is not defined& ...

Converting ed25519 private key into OpenSSH Format using JavaScript

After generating an ed25519 key pair using the javascript crypto library, I am now faced with the challenge of saving the private key in openssh format. Despite attempting to use the sshpk library for this task, I encountered an issue where the exported k ...

How can I represent non-ASCII characters in Java Script using encoding?

Imagine if ch = á the desired result is = \u00e1 however the current output = %E1 when escape(ch) is used and current output = %C3%A1 when encodeURIComponent(ch) is used I am working with an API that supports Unicode characters. ...

Save the result of a terminal command into an sqlite database

When I run a particular shell command in node js, the output is displayed on the console. Is there a method to store this output in a variable so that it can be POSTed to an Sqlite database? const shell = require('shelljs'); shell.exec('a ...

Javascript continuously swaps out text from distinct strings in a loop

I wrote a loop to split a string and search for certain text to replace it with another string. Here is an example of what I have done: function replaceStr(str, find, replace) { for (var i = 0; i < find.length; i++) { str = str.replace(new RegE ...

Tips for successfully transferring an image through an XMLHttpRequest

I found this helpful resource at: I decided to test out the second block of code. When I made changes in the handleForm function, it looked like this: function handleForm(e) { e.preventDefault(); var data = new FormData(); f ...

Rotating an object in THREE js along a single axis to face the camera independently of its parent's influence

Here's my current scenario: var camera = new THREE.PerspectiveCamera(...); scene.add(camera); var parent = new THREE.Object3D(); parent.position.set(1,2,3); scene.add(parent); var child = new THREE.Object3D(); ...

How can you enable a button to be clicked from within a drawer?

Hey there, I've got a div that toggles hide/show like a drawer when clicked. When the drawer is in show state, it contains a button. How can I make the button clickable without toggling the drawer? Any ideas on this?! `zIndex` doesn't seem to be ...

What is the best way to showcase the properties of multiple files with the help of

I have been attempting to utilize jQuery to exhibit the specifics of several uploaded files. Below is my code: <!DOCTYPE html> <html> <head> <title>jQuery Multi File Upload</title> </head> <body> <f ...

Creating a Dynamic Form with jQuery, AJAX, PHP, and MySQL for Multiple Input Fields

Success! The code is now functional. <form name="registration" id="registration" action="" method="post"> <div id="reg_names"> <div class="control-group"> <label>Name</label> <div class= ...

Applying custom styles to the initial 5 elements post clicking the button with Jquery

I have a set of HTML codes containing multiple buttons. <div class="main"> <div class="button hide">1</div> <div class="button hide">2</div> <div class="button hide">3</div> <div class="button h ...

Navigating between Vue Router pages triggers multiple events within the mounted() lifecycle of VueJS

Currently, I am immersed in a project using Electron with a Vue CLI setup and the Vue CLI Plugin Electron Builder. The overall functionality is working perfectly fine except for a peculiar bug that has recently surfaced. The issue arises when navigating b ...