Adding a map and roughnessMap in ThreeJS: A beginner's guide

Below is the code snippet I am currently working on:

* {
  margin: 0;
  padding: 0;
}

.object {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  background-color: rgb(200, 200, 200);
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import { OBJLoader } from "https://threejs.org/examples/jsm/loaders/OBJLoader.js";
import { EXRLoader } from "https://threejs.org/examples/jsm/loaders/EXRLoader.js";

var container;
var camera, scene, renderer;
let exrCubeRenderTarget, exrBackground;
let newEnvMap;
let torusMesh, planeMesh;

var mouseX = 0,
    mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var object;

init();
animate();

function init() {
    container = document.createElement("div");
    container.className = "object";
    document.body.appendChild(container);

    camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        2000
    );
    camera.position.z = 250;

    // scene

    scene = new THREE.Scene();

    /*var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
    scene.add(ambientLight);
    var pointLight = new THREE.PointLight(0xffffff, 2);
    pointLight.position.set(100, 100, 50);
    camera.add(pointLight);*/

    scene.add(camera);

    // manager
    function loadModel() {
        THREE.DefaultLoadingManager.onLoad = function () {
            pmremGenerator.dispose();
        };

        // -----------------

        function loadObjectAndAndEnvMap() {
            object.traverse(function (child) {
                //This allow us to check if the children is an instance of the Mesh constructor
                if (child instanceof THREE.Mesh) {
                    child.material = new THREE.MeshStandardMaterial({
                        color: "#555",
                        roughness: 0.0,
                        metalness: 2.0,
                        envMapIntensity: 5.0
                    });
                    //child.material.flatShading = false;

                    console.log("setting envmap");
                    child.material.envMap = newEnvMap;
                    child.material.needsUpdate = true;

                    //Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
                }
            });
            object.position.y = -90;
            scene.add(object);
        }

        const pmremGenerator = new THREE.PMREMGenerator(renderer);
        pmremGenerator.compileEquirectangularShader();

        new EXRLoader()
            .setDataType(THREE.UnsignedByteType)
            .load(
                "https://threejs.org/examples/textures/piz_compressed.exr",
                function (texture) {
                    exrCubeRenderTarget = pmremGenerator.fromEquirectangular(texture);
                    exrBackground = exrCubeRenderTarget.texture;
                    newEnvMap = exrCubeRenderTarget ? exrCubeRenderTarget.texture : null;

                    loadObjectAndAndEnvMap(); // Add envmap once the texture has been loaded

                    texture.dispose();
                }
            );

        renderer.toneMapping = THREE.ACESFilmicToneMapping;
        renderer.outputEncoding = THREE.sRGBEncoding;
    }

    var manager = new THREE.LoadingManager(loadModel);

    manager.onProgress = function (item, loaded, total) {
        console.log(item, loaded, total);
    };

    // model
    function onProgress(xhr) {
        if (xhr.lengthComputable) {
            var percentComplete = (xhr.loaded / xhr.total) * 100;
            console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
        }
    }
    function onError() {}
    var loader = new OBJLoader(manager);
    loader.load(
        "https://threejs.org/examples/models/obj/female02/female02.obj",
        function (obj) {
            object = obj;
        },
        onProgress,
        onError
    );

    //

    renderer = new THREE.WebGLRenderer({ alpha: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);

    document.addEventListener("mousemove", onDocumentMouseMove, false);

    //

    window.addEventListener("resize", onWindowResize, false);
}

function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event) {
    mouseX = (event.clientX - windowHalfX) / 2;
    mouseY = (event.clientY - windowHalfY) / 2;
}

//

function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (-mouseY - camera.position.y) * 0.05;

    camera.lookAt(scene.position);

    scene.background = exrBackground;
    renderer.toneMappingExposure = 1.0;
    renderer.render(scene, camera);
}
</script>

I have a requirement to include map and roughnessMap similar to this example here: https://threejs.org/docs/scenes/material-browser.html#MeshStandardMaterial

My understanding was that by adding the following lines, it should work:

const textureLoader = new THREE.TextureLoader();


const diffuseMaps = (function() {

  const bricks = textureLoader.load('https://threejs.org/examples/textures/brick_diffuse.jpg');
  bricks.wrapS = RepeatWrapping;
  bricks.wrapT = RepeatWrapping;
  bricks.repeat.set(9, 1);

  return {
    none: null,
    bricks: bricks
  };

})();


const roughnessMaps = (function() {

  const bricks = textureLoader.load('https://threejs.org/examples/textures/brick_roughness.jpg');
  bricks.wrapT = RepeatWrapping;
  bricks.wrapS = RepeatWrapping;
  bricks.repeat.set(9, 1);

  return {
    none: null,
    bricks: bricks
  };

})();


function loadObjectAndAndEnvMap() {
  object.traverse(function(child) {
    //This allow us to check if the children is an instance of the Mesh constructor
    if (child instanceof THREE.Mesh) {
      child.material = new THREE.MeshStandardMaterial({
        color: "#555",
        roughness: 0.0,
        metalness: 2.0,
        envMapIntensity: 5.0,
        diffuseMapIntensity: 1.0,
        roughnessMapIntensity: 1.0
      });
      //child.material.flatShading = false;

      console.log("setting envmap");
      child.material.envMap = newEnvMap;
      child.material.diffuseMap = diffuseMaps;
      child.material.roughnessMap = roughnessMaps;
      child.material.needsUpdate = true;

      //Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
    }
  });
  object.position.y = -90;
  scene.add(object);
}

Unfortunately, my implementation is not causing the intended effect.

If anyone could assist me with this issue, I would greatly appreciate it!

Answer №1

Give this code a try:

var container;
var camera, scene, renderer;
let exrCubeRenderTarget, exrBackground;
let newEnvMap;
let torusMesh, planeMesh;

var mouseX = 0,
  mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var object;

init();
animate();

function init() {
  container = document.createElement("div");
  container.className = "object";
  document.body.appendChild(container);

  camera = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    1,
    2000
  );
  camera.position.z = 250;

  // scene

  scene = new THREE.Scene();
  scene.add(camera);

  // manager
  function loadModel() {
    THREE.DefaultLoadingManager.onLoad = function() {
      pmremGenerator.dispose();
    };

    // -----------------

    function loadObjectAndAndEnvMap() {
    
      const textureLoader = new THREE.TextureLoader();
      const diffuseMap = textureLoader.load('https://threejs.org/examples/textures/brick_diffuse.jpg');
      const roughnessMap = textureLoader.load('https://threejs.org/examples/textures/brick_roughness.jpg');
    
      object.traverse(function(child) {
        //This allow us to check if the children is an instance of the Mesh constructor
        if (child instanceof THREE.Mesh) {
          child.material = new THREE.MeshStandardMaterial({
            color: "#555",
            roughness: 1.0,
            metalness: 0.5,
            envMapIntensity: 5.0
          });

          child.material.envMap = newEnvMap;
          child.material.map = diffuseMap;
          child.material.roughnessMap = roughnessMap;
          child.material.needsUpdate = true;

          //Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
        }
      });
      object.position.y = -90;
      scene.add(object);
    }

    const pmremGenerator = new THREE.PMREMGenerator(renderer);
    pmremGenerator.compileEquirectangularShader();

    new THREE.EXRLoader()
      .setDataType(THREE.UnsignedByteType)
      .load(
        "https://threejs.org/examples/textures/piz_compressed.exr",
        function(texture) {
          exrCubeRenderTarget = pmremGenerator.fromEquirectangular(texture);
          exrBackground = exrCubeRenderTarget.texture;
          newEnvMap = exrCubeRenderTarget ? exrCubeRenderTarget.texture : null;

          loadObjectAndAndEnvMap(); // Add envmap once the texture has been loaded

          texture.dispose();
        }
      );

    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.outputEncoding = THREE.sRGBEncoding;
  }

  var manager = new THREE.LoadingManager(loadModel);

  manager.onProgress = function(item, loaded, total) {
    console.log(item, loaded, total);
  };


  var loader = new THREE.OBJLoader(manager);
  loader.load(
    "https://threejs.org/examples/models/obj/female02/female02.obj",
    function(obj) {
      object = obj;
    }
  );

  //

  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.appendChild(renderer.domElement);

  document.addEventListener("mousemove", onDocumentMouseMove, false);

  //

  window.addEventListener("resize", onWindowResize, false);
}

function onWindowResize() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event) {
  mouseX = (event.clientX - windowHalfX) / 2;
  mouseY = (event.clientY - windowHalfY) / 2;
}

//

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  camera.position.x += (mouseX - camera.position.x) * 0.05;
  camera.position.y += (-mouseY - camera.position.y) * 0.05;

  camera.lookAt(scene.position);

  scene.background = exrBackground;
  renderer.toneMappingExposure = 1.0;
  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="e7938f958282a7d7c9d6d5d2c9d5">[email protected]</a>/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2f5b475d4a4a6f1f011e1d1a011d">[email protected]</a>/examples/js/loaders/OBJLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c7b3afb5a2a287f7e9f6f5f2e9f5">[email protected]</a>/examples/js/loaders/EXRLoader.js"></script>

Important note:

  • The maximum value for roughness and metalness should not exceed 1. You have used 2 for metalness.
  • If you set the roughness value to 0, it might not produce any visible effect as it interacts with the texture map. It's recommended to start with 1 for best results.

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

Choosing between global and local Node packages can be a crucial decision that affects

Recently, I discovered that Angular 2 is installed globally on my system, but I can't remember when I did that or if it's the recommended setup. It seems redundant since Angular can be defined in each project individually. This situation has me ...

Changing jQuery to plain JavaScript in order to show a div element more effectively

I am attempting to toggle a checkbox to display a header or div that is currently hidden. @media screen and (max-width: 639.98px){ #menuPanel{ display: none !important; } } I am encountering an unresolved method error on ready in JQuery, ...

Is it possible to restrict movement along the x, y, and z axes in ThreeJs?

While using ThreeJS and firstpersoncontrols to control camera movement, I am looking to set boundaries for the viewer's movement in the x and z directions. Is there a property available for this purpose? I have attempted to adjust the code in firstPe ...

Remove an image that has been selected while uploading multiple images using AngularJS

If I want to delete a specific image from multiple uploads by clicking on the image in AngularJS, how can I achieve this? Each uploaded image has an associated textbox. When the delete icon on the image is clicked, both the image and the corresponding text ...

The webpage becomes unresponsive and crashes within a matter of minutes

When my website is hosted on a server, it becomes unresponsive, freezes, and crashes after a few minutes. However, everything works fine when I run it locally on localhost while pulling API data from a Flask Server app. The Flask-based API engine retrieve ...

What's the best way to send query parameters or body data in NextJS with Auth0 integration?

I have very limited knowledge of Next.js and JS in general, as well as Auth0. I'm looking for help on how to pass query parameters or a request body to the first block of code below. I understand that I can include a body in the fetch function, but w ...

Retrieve the current global time accurately, utilizing an API to access internet-based time data within a React js framework

Seeking a way to retrieve current international time in React Js using internet const date = new Date(); The above code snippet retrieves the current device time, but I need an alternative solution. The issue is that when I change my device's time se ...

Revise my perspective on a modification in the backbone model

I am new to using Backbone and I am currently practicing by creating a blog using a JSON file that contains the necessary data. Everything seems to be working, although I know it might not be the best practice most of the time. However, there is one specif ...

Picking a variety of elements and determining their heights using the height

I'm curious why this jQuery code isn't working as expected: hdr = $('.header-wrapper, #top-bar, #new-showroom-header').height(); My intention is to retrieve the heights of multiple elements and store them in a variable. I assumed that ...

Ways to eliminate the gap between the currency symbol and the numerical value in HTML

Is there a way to eliminate the gap between the Currency Symbol and Amount? I've been attempting to get rid of the space between the currency symbol and the amount in my HTML code. However, even when I input decimals, there remains a gap between the ...

What is the best way to change an email address in meteor?

Hey there! I'm currently working on an app using Meteor and I need to update my email address. The process involves utilizing the Meteor accounts package. In my form, I pass an email value into an accountDetails object, which will then be used in a m ...

Ways to incorporate additional values into an array object with Vuex

I'm new to using vuex and I am attempting to save objects into an array called orders within the store.js file. My goal is to extract values from an object (such as me.title) and save them into an array within the store file by clicking on a button t ...

This module is not compatible with the "node" engine when trying to install React-chartjs-2 Chart.js

While working on a new project, I successfully implemented a doughnut chart using chart.js and its react wrapper. However, when attempting to install it in the main project, I encountered some difficulties. Here is an example of the new project where the ...

Updating line connections between objects in Three.js while rendering

I am working with a three.js canvas that contains circles moving independently. Initially, these circles are connected by a single line that follows the same geometry as their positions. However, I am facing difficulty updating the line's geometry wh ...

Replacing the absence of value with an empty string within a textfield using Lit-element

In my current project, I am utilizing Lit-element and mwc-element. Within this setup, I have two string variables and an object variable that holds the string values. My goal is to populate a text-field with these object values. So far, I have managed to a ...

Package an npm module and transform it into an ECMAScript module

I'm trying to incorporate the chessground library into one of my projects. It appears to be a CommonJS module, so I utilized browserify to bring it into my web page. browserify -r chessground > chessground.js To make use of it on my webpage, I am ...

Tips for modifying the hue of the hint attribute within vue.js?

`<v-text-field id="loginPasswordId" ref="password" v-model="password" class="login-input" dense :disabled="loading" :hint="hello world" :loading="loading" maxlength= ...

Using Jquery to create animations when hovering over an element

I cannot figure out what's going on with this script, it just won't cooperate. The intended behavior is for the box to fade its color in and out based on mouse enter/leave actions. $(document).ready(function() { $('.square-box').mo ...

Using Express.js, the require() method is called, followed by a function that takes

I'm relatively new to Node.js and Express. While browsing tutorials and examples, I came across the following code snippet inside app.js: var router = require('./router')(app); I'm curious about the purpose of this line of code. What ...

Modify the javascript addEventListener to use 'scroll' instead of 'wheel'

I am currently attempting to modify this javascript event to trigger on scroll instead of the mouse wheel. I have attempted to make the following changes: window.addEventListener('wheel',function (e) changed to window.addEventListener('sc ...