I am importing a glTF
model into a WebGL
ThreeJS
scene. In the gltf-viewer.donmccurdy.com
preview I can see that the environment setting makes a big difference to how my model renders:
This is how it looks without the environment map:
So I am loading a jpg
texture to use as the environment map and then loading my glTF
and adding the texture as the loaded models scene.environment
property. Here's the main chunk of the code:
import * as THREE from "three";
import { GLTFLoader } from "GLTFLoader";
// import { EXRLoader } from "EXRLoader";
export class AppController {
constructor(app) {
this.app = app;
}
animate = () => {
requestAnimationFrame( this.animate );
this.renderer.render( this.scene, this.camera );
}
init = () => {
console.log('AppController.init()');
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
this.scene.background = new THREE.Color( 0x00ffff );
const light = new THREE.AmbientLight( 0x404040 ); // soft white light
this.scene.add( light );
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize( window.innerWidth, window.innerHeight );
this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
this.renderer.outputEncoding = THREE.sRGBEncoding;
document.body.appendChild( this.renderer.domElement );
this.camera.position.z = 100;
const fthis = this;
new THREE.TextureLoader().load("./assets/images/env.jpg",
function ( texture ) {
fthis.scene.environment = texture;
fthis.loadModel(texture);
},
undefined,
function ( err ) {
console.error( err );
});
this.animate();
}
loadModel = (texture) => {
const loader = new GLTFLoader();
const modelPath = 'assets/models/Pebble_Logo_Extrude.gltf';
const fthis = this;
loader.load( modelPath, function ( gltf ) {
console.log('gltf', gltf);
fthis.pebbleLogo = gltf;
fthis.pebbleLogo.scene.environment = texture;
fthis.pebbleLogo.scene.traverse(function (child) {
if (child instanceof THREE.Mesh) {
if(child.material !== null){
console.log("setting envmap");
child.material.envMap = texture;
child.material.metalness = 0.0;
child.material.envMapIntensity = 2.0;
child.material.needsUpdate = true;
}
}
});
fthis.scene.add( fthis.pebbleLogo.scene );
}, undefined, function ( error ) {
console.error( error );
} );
}
}
As you can see, the environment map has had no effect at all.
I did read something about possibly needing to use the EXRLoader
to make the map, but this was an old article and I assumed this may no longer be the case seeing as Three
doesn't include in their documentation.
Any help most appreciated.
CodePudding user response:
Before assigning the environment map to Scene.environment
, you need the following line of code:
texture.mapping = THREE.EquirectangularReflectionMapping;
This defines that your loaded texture is in the equirectangular format.
Besides, if you load a LDR environment map, you want to add the following line, too:
texture.encoding = THREE.sRGBEncoding;
BTW: If you use no HDR environment map, there is no need to configure tone mapping. So you can remove:
this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
CodePudding user response:
In the examples source, you'll see they are using RGBELoader
to get the texture for the environment mapping. This is all you need. My updated code:
import * as THREE from "three";
import { GLTFLoader } from "GLTFLoader";
import { RGBELoader } from "RGBELoader";
export class AppController {
constructor(app) {
this.app = app;
}
animate = () => {
requestAnimationFrame( this.animate );
this.renderer.render( this.scene, this.camera );
}
init = () => {
console.log('AppController.init()');
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
this.scene.background = new THREE.Color( 0x00ffff );
const light = new THREE.AmbientLight( 0x404040 ); // soft white light
this.scene.add( light );
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize( window.innerWidth, window.innerHeight );
this.renderer.shadowMap.enabled = true;
this.renderer.outputEncoding = THREE.sRGBEncoding;
document.body.appendChild( this.renderer.domElement );
this.camera.position.z = 50;
const fthis = this;
new RGBELoader()
.setPath( 'assets/images/' )
.load( 'venice_sunset_1k.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
fthis.scene.environment = texture;
fthis.loadModel(texture);
} );
this.animate();
// get the mouse position
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2();
// setup listeners
document.addEventListener('mousemove', this.onDocumentMouseMove, false);
window.addEventListener('resize', this.onWindowResize, false);
}
onDocumentMouseMove = (event) => {
event.preventDefault();
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.clientY / window.innerHeight) * 2 1;
}
onWindowResize = () => {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
loadModel = (texture) => {
const loader = new GLTFLoader();
const modelPath = 'assets/models/Pebble_Logo_Extrude.gltf';
const fthis = this;
loader.load( modelPath, function ( gltf ) {
console.log('gltf', gltf);
fthis.pebbleLogo = gltf;
fthis.scene.add( fthis.pebbleLogo.scene );
}, undefined, function ( error ) {
console.error( error );
} );
}
}