UPDATE :
implemented some modifications in repetition of tiles texture & grout creation. facing issue as images are getting stretched a bit.
also on camera movement changes how can we restrict the wall mesh movement ?
function loadTextureAndSetRepeat({ element, rotateAngle = 0 }) {
let surfaceData = element.userData;
let randomIndex = Math.floor(Math.random() * tilesData.length);
let currentTexture = tilesData[randomIndex];
const imageUrls = currentTexture.imgUrl;
// Convert surfaceData width and height from feet to meters
const feetToMeters = 0.3048;
const wallWidthMeters = surfaceData.width * feetToMeters;
const wallHeightMeters = surfaceData.height * feetToMeters;
const createTextureWithGrout = (images, widthMeters, heightMeters) => {
const tileWidthMeters = 6; // Tile width in meters (600mm)
const tileHeightMeters = 6; // Tile height in meters (600mm)
const groutThicknessMeters = 0.2; // Grout thickness in meters (5mm)
const columns = Math.ceil(widthMeters / tileWidthMeters);
const rows = Math.ceil(heightMeters / tileHeightMeters);
// Create a canvas to draw the combined texture
const canvas = document.createElement('canvas');
canvas.width = Math.ceil((tileWidthMeters * columns) * 100); // Convert to pixels
canvas.height = Math.ceil((tileHeightMeters * rows) * 100); // Convert to pixels
const context = canvas.getContext('2d');
// Check if images are loaded before proceeding
if (images.some(image => !image.complete || image.naturalWidth === 0)) {
throw new Error('One or more images failed to load.');
}
// Draw each image with grout lines
for (let col = 0; col < columns; col++) {
for (let row = 0; row < rows; row++) {
const x = col * tileWidthMeters * 100;
const y = row * tileHeightMeters * 100;
const image = images[(row * columns + col) % images.length];
// Create a temporary canvas to draw the tile with grout
const tileCanvas = document.createElement('canvas');
tileCanvas.width = tileWidthMeters * 100;
tileCanvas.height = tileHeightMeters * 100;
const tileContext = tileCanvas.getContext('2d');
// Draw the tile image on the temporary canvas
tileContext.drawImage(image, 0, 0, tileCanvas.width, tileCanvas.height);
// Draw the grout lines on the tile image
tileContext.fillStyle = 'rgb(255, 0, 0)'; // Red grout color
// Draw vertical grout lines
tileContext.fillRect(tileCanvas.width - groutThicknessMeters * 100, 0, groutThicknessMeters * 100, tileCanvas.height);
// Draw horizontal grout lines
tileContext.fillRect(0, tileCanvas.height - groutThicknessMeters * 100, tileCanvas.width, groutThicknessMeters * 100);
// Draw the modified tile image on the main canvas
context.drawImage(tileCanvas, x, y);
}
}
// Create the Three.js texture from the canvas
const texture = new THREE.CanvasTexture(canvas);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.rotation = Math.PI * tileTextureRotation;
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
return texture;
};
const loadImages = (urls) => {
return Promise.all(urls.map((url) => {
return new Promise((resolve, reject) => {
const image = new Image();
image.crossOrigin = "anonymous"; // To handle CORS issues
image.onload = () => resolve(image);
image.onerror = (error) => reject(error);
image.src = url;
});
}));
};
loadImages(imageUrls)
.then((images) => {
const combinedTexture = createTextureWithGrout(images, wallWidthMeters, wallHeightMeters);
// Assign texture to element material in Three.js
element.material.map = combinedTexture;
element.material.needsUpdate = true;
// Render scene
renderer.render(scene, camera);
})
.catch((error) => {
console.error('Error loading images:', error);
});
}
walls & scene creation
// Function to create a skybox
const createSkybox = async (layoutType, texturesArray) => {
try {
const textures = await Promise.all(texturesArray.map(loadTexture));
const materials = textures.map(
(texture) =>
new THREE.MeshBasicMaterial({
map: texture,
side: THREE.BackSide, // Make sure the textures are on the inside
transparent: true,
opacity: 1,
blending:
layoutType === "base"
? THREE.NormalBlending
: THREE.MultiplyBlending,
})
);
const geometry = new THREE.BoxGeometry(100, 100, 100); // Large enough to act as a skybox
const skybox = new THREE.Mesh(geometry, materials);
skybox.rotation.y = -Math.PI / 2;
return skybox;
} catch (error) {
console.error("Error loading textures for skybox:", error);
}
};
// Load and add skyboxes to the scene
Promise.all([
createSkybox("base", texturesMap.transparent),
createSkybox("glossy", texturesMap.matt),
createSkybox("matt", texturesMap.glossy),
]).then((skyboxes) => {
[transparentSkybox, mattSkybox, glossySkybox] = skyboxes;
// Add skyboxes to the scene
if (mattSkybox) {
group.add(mattSkybox);
mattSkybox.visible = false; // Set the matt skybox invisible by default
}
if (glossySkybox) {
group.add(glossySkybox);
glossySkybox.visible = true; // Set the glossy skybox visible by default
}
if (transparentSkybox) {
group.add(transparentSkybox);
transparentSkybox.visible = true; // Set the transparent skybox visible by default
}
const ambientLight = new THREE.AmbientLight(0xffffff, informazione.intensity);
scene.add(group);
scene.add(ambientLight);
//create walls
for (const element of data) {
if (element.face.toLowerCase() === "wall") {
const wallGeometry = new THREE.PlaneGeometry(
element.width,
element.height
);
const wallMaterial = new THREE.MeshBasicMaterial({
map: defaultFloorTexture, // Use default texture
side: THREE.DoubleSide,
depthTest: true,
});
const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
wallMesh.userData = element;
wallMesh.position.set(
element["position-x"],
element["position-y"],
element["position-z"]
);
wallMesh.rotation.y = element["rotation-y"];
wallMesh.rotation.x = element.rotateX;
group.add(wallMesh);
}
if (element.face.toLowerCase() === "floor") {
const floorGeometry = new THREE.PlaneGeometry(
element.width,
element.height
);
const floorMaterial = new THREE.MeshBasicMaterial({
map: defaultFloorTexture, // Use default texture
side: THREE.DoubleSide,
depthTest: true,
});
const floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
let dataObj = element;
floorMesh.userData = dataObj;
floorMesh.position.set(
element["position-x"],
element["position-y"],
element["position-z"]
);
floorMesh.rotation.x = Math.PI / 2;
group.add(floorMesh);
}
}
scene.add(group);
animate();
});
another issue is when I try to apply texture on floor, getting issues and texture isn’t getting applied
Thanks