Hi, I’m using three.js and next.js for a project and i want to load a ktx2 files to use them as a cubemap, in the console i can see that they are loaded but it doesn’t seems to show, the cubemap go from black to dark gray and that is it, here is my code:
“use client”;
import React, { useEffect, useRef } from “react”;
import * as THREE from “three”;
import gsap from “gsap”;
import { KTX2Loader } from “…/node_modules/three/examples/jsm/loaders/KTX2Loader”;
const MainCanvas = () => {
const mount = useRef(null);
const init = () => {
const loadingBar = document.querySelector(“.loading-bar”);
const loadingManager = new THREE.LoadingManager(
() => {
setTimeout(() => {
window.scrollTo(0, 0);
gsap.to(camera.position, {
duration: 1,
delay: 1,
z: 128,
y: 20,
});
}, 50);
},
(itemUrl, itemsLoaded, itemsTotal) => {
const progressRatio = itemsLoaded / itemsTotal;
loadingBar.style.transform = "scaleX(" + progressRatio + ")";
}
);
// Scene
const scene = new THREE.Scene();
// scene.background = envMap;
// Objects
const Group = new THREE.Group();
scene.add(Group);
const LambertMaterial = new THREE.MeshLambertMaterial({
color: 0xffffff,
side: THREE.DoubleSide,
});
const plane = new THREE.Mesh(
new THREE.PlaneGeometry(
window.innerWidth * 1.25,
window.innerHeight * 1.25,
window.innerWidth / 2,
window.innerHeight / 2
),
LambertMaterial
);
Group.add(plane);
plane.rotation.x = -Math.PI / 2 - 0.2;
plane.position.y = -25;
plane.position.z = -60;
const donutGeometry = new THREE.BufferGeometry(0.3, 0.2, 20, 45);
const dodecahedronGeometry = new THREE.OctahedronGeometry(0.4, 0);
const sphereBufferGeometry = new THREE.OctahedronGeometry(0.7, 7);
let obj;
for (let i = 0; i < 125; i++) {
switch (Math.floor(Math.random() * 3)) {
case 0:
obj = new THREE.Mesh(donutGeometry, LambertMaterial);
break;
case 1:
obj = new THREE.Mesh(dodecahedronGeometry, LambertMaterial);
break;
case 2:
obj = new THREE.Mesh(sphereBufferGeometry, LambertMaterial);
break;
default:
obj = new THREE.Mesh(dodecahedronGeometry, LambertMaterial);
break;
}
obj.position.set(
(Math.random() - 0.5) * 200,
(Math.random() - 0.5) * 10 + 5,
(Math.random() - 0.5) * 200
);
obj.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
scene.add(obj);
}
// Sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
};
// Lights
const initLights = () => {
const r = 30;
const y = 10;
const lightDistance = 500;
const light1 = new THREE.PointLight(0x0e09dc, 0.4, lightDistance);
light1.position.set(0, y, r - 60);
scene.add(light1);
const light2 = new THREE.PointLight(0x1cd1e1, 0.4, lightDistance);
light2.position.set(0, -y, -r - 60);
Group.add(light2);
const light3 = new THREE.PointLight(0x18c02c, 0.4, lightDistance);
light3.position.set(r, y, -60);
scene.add(light3);
const light4 = new THREE.PointLight(0xee3bcf, 0.4, lightDistance);
light4.position.set(-r, y, -60);
Group.add(light4);
};
initLights();
// Camera
const camera = new THREE.PerspectiveCamera(
80,
sizes.width / sizes.height,
0.1,
400
);
camera.position.set(0, 75, 325);
Group.add(camera);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
mount.current.appendChild(renderer.domElement);
const ktx2Loader = new KTX2Loader(loadingManager)
.setTranscoderPath("/basis/")
.detectSupport(renderer);
const cubemapFaces = [
"px.ktx2",
"nx.ktx2",
"py.ktx2",
"ny.ktx2",
"pz.ktx2",
"nz.ktx2",
];
const envMapPromises = cubemapFaces.map((face) => {
return new Promise((resolve, reject) => {
ktx2Loader.load(
`/ktx/${face}`,
(texture) => {
resolve(texture);
},
undefined,
(error) => {
reject(error);
}
);
});
});
let envMap = Promise.all(envMapPromises)
.then((textures) => {
console.log(textures);
textures.minFilter = THREE.NearestMipmapNearestFilter;
const envMap = new THREE.CubeTexture(textures);
console.log(envMap);
// Use envMap in your scene
scene.background = envMap;
return envMap;
})
.catch((error) => {
console.error("Error loading KTX2 cubemap:", error);
});
if (envMap) {
scene.background = envMap;
}
// Update Resizes
const handleResize = () => {
// Update sizes
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
// Update camera
if (sizes.width > 600) {
camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix();
// Update
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
}
};
window.addEventListener("resize", handleResize);
const clock = new THREE.Clock();
const tick = () => {
const elapsedTime = clock.getElapsedTime();
// Render
renderer.render(scene, camera);
// Call tick again on the next frame
requestAnimationFrame(tick);
};
tick();
};
useEffect(() => {
init();
}, ); // empty dependency array ensures that the effect runs once on mount
return
;
};
};
export default MainCanvas;