I’ve created a gallery of sorts within Blender with lots around 50 Images (all under around 300kb) each but when I load everything in three when looking in the direction of where all these Images are, my frames drop lots. (The lag happens when I’m looking through walls of the model).
I was wondering if there are any suggestions to reduce this lag? I assume it’s the number of images being loaded in so I’m considering combining multiple Images into one but not sure if that’s going to fix it.
Or if there is any way to unload images within a range of the camera as I’m using pointerlock controls? However they are connected to the GLTF file in the same folder with the AO and UVmapping.
Any suggestions would really be appreciated! Cheers.
Unsure about that - 50 x 300kb shouldn’t be too much to handle (although it may be lagging during the loading, if you’re sending separate requests for the images.)
Would it be possible for you to share the model (can be without the images, just placeholders with similar file size or resolution) or code?
Images are uploaded to the GPU the first time they are rendered. If frames are being dropped, interrupting rendering, this is usually the cause. Combining images typically won’t help with it. You could upload every texture ahead of time (e.g. while showing a loading screen) so that it’s all ready to go before the application starts.
There may be other options like Basis Universal or decreasing texture resolution, but it’s hard to say without access to the model.
I also just noticed that my file sizes have changed from initlally importing them in blender to exporting them in GLTF. I attempted to just replacing the files from the GLTF source files but that broke the model loading.
My code is here:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<!-- <div class="scene"></div> -->
<script src="libraries/three.min.js"></script>
<script src="libraries/PointerLockControls.js"></script>
<script src="libraries/OrbitControls.js"></script>
<script src="libraries/GLTFLoader.js"></script>
<video id="video" loop crossOrigin="anonymous" playsinline style="display:none" muted >
<!-- <source src="sound/aaron.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg"> -->
</video>
<section id="loading-screen">
<div id="loader"></div>
</section>
<script>
let scene,camera,renderer, controls, model;
function init(){
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xFFFFFF );
// fog
{
const color = 0xFFFFFF;
const near = 10;
const far = 500;
scene.fog = new THREE.Fog(color, near, far);
}
var video = document.getElementById( 'video' );
var texture = new THREE.VideoTexture(video);
// texture.needsUpdate;
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
texture.crossOrigin = 'anonymous';
var imageObject = new THREE.Mesh(
new THREE.PlaneBufferGeometry(72/2, 45/2),
new THREE.MeshBasicMaterial({ map: texture }),);
scene.add( imageObject );
video.src = "sound/aaron.mp4";
video.load();
video.play();
imageObject.position.set(82,5,-318);
//Camera Things
camera = new THREE.PerspectiveCamera( 60, window.innerWidth/ window.innerHeight, 0.1, 5000 );
camera.position.set(200,0,0);
console.log(camera.position);
// Lighting Things
const ambient = new THREE.AmbientLight(0xFFFFFF,0.9);
scene.add(ambient);
// Renderer
renderer = new THREE.WebGLRenderer({ antialias:true});
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild( renderer.domElement );
// controls
controls = new THREE.PointerLockControls(camera, renderer.domElement);
// controls = new THREE.OrbitControls(camera, renderer.domElement);
document.body.addEventListener( 'click', function () {
controls.lock();
}, false );
scene.add( new THREE.AxesHelper(500));
// controls.update();
camera.position.y = 1;
camera.position.z = 2;
var onKeyDown = function (event) {
switch (event.keyCode) {
case 87: // w
controls.moveForward(2.4);
break;
case 65: // a
controls.moveRight(-2.4);
break;
case 83: // s
controls.moveForward(-2.4);
break;
case 68: // d
controls.moveRight(2.4);
break;
}
};
document.addEventListener('keydown', onKeyDown, false);
}
// Load Model
new THREE.GLTFLoader().load('3d/Alpha/a2.gltf', result => {
model = result.scene;
model.position.set(0,-28,-340);
scene.add(model);
});
// basic Animation
function animate() {
// controls.update();
requestAnimationFrame( animate );
renderer.render( scene, camera);
};
init();
animate();
// Resize function
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix( );
renderer.setSize(window.innerWidth , window.innerHeight);
};
window.addEventListener('resize',onWindowResize,false);
</script>
</body>
</html>
Pay attention to the “resolution” and “memSize” columns… even if you re-compress the images to the ~15MB they were before Blender altered them, WebGL has to decompress them all completely before uploading to the GPU, so it’s really uploading hundreds of megabytes here. Unfortunately, even a 10kb PNG could be many megabytes after it is decompressed.
I expect it would be the same, except that maybe it would be easier to control exactly when each texture gets loaded. So, maybe, you could spread out the lag of the uploads more.
Another option to consider — remove the textures from all the “label” objects, and instead put their text onto “Custom Properties” on the object in Blender. Enable the “Export custom properties” option at export, and you’ll get their values in three.js objects’ .userData, so you could do something like this assuming your custom property’s name is “MyLabel”:
scene.traverse((o) => {
if (o.userData.MyLabel) {
o.add( new THREE.Mesh( new THREE.TextGeometry( o.userData.MyLabel ) ) );
}
});
… It’d be a bit more complicated than that to get the text exactly where you want it, of course, but you can adjust the positioning.
EDIT: Also note that TextGeometry requires a .font parameter which I didn’t include above. See three.js docs.