how to set tile texture on transperent wall in 360 view(using 6 cube img)

here is my code :
import React, { useEffect, useState } from ‘react’;
import { useThree } from ‘@react-three/fiber’;
import * as THREE from ‘three’;

interface PanoramaViewerProps {
cubeImages: string;
tileTexture: string; // Add a prop for the texture tile image
}

const PanoramaViewer: React.FC = ({ cubeImages, tileTexture }) => {
const { scene, camera } = useThree();
const [hoveredUV, setHoveredUV] = useState<THREE.Vector2 | null>(null);
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const canvas = document.createElement(‘canvas’);
let texture: THREE.CubeTexture;

useEffect(() => {
// Load the cube texture for the 360 view
const loader = new THREE.CubeTextureLoader();
texture = loader.load(cubeImages, () => {
const img = texture.image[0]; // Assuming the texture images are consistent
canvas.width = img.width;
canvas.height = img.height;

  const context = canvas.getContext('2d');
  if (context) {
    context.drawImage(img, 0, 0, canvas.width, canvas.height);
  }
});

// Apply the texture to the background
scene.background = texture;

return () => {
  // Cleanup
  if (scene.background === texture) {
    scene.background = null;
  }
};

}, [cubeImages, scene]);

const onMouseMove = (event: MouseEvent) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(camera as THREE.Object3D);

if (intersects.length > 0) {
  const uv = intersects[0].uv;
  if (uv) {
    checkTransparencyAtUV(uv);
  } else {
    setHoveredUV(null);
  }
} else {
  setHoveredUV(null);
}

};

const checkTransparencyAtUV = (uv: THREE.Vector2) => {
const context = canvas.getContext(‘2d’);
if (!context) return;

const x = Math.floor(uv.x * canvas.width);
const y = Math.floor(uv.y * canvas.height);

if (x < 0 || x >= canvas.width || y < 0 || y >= canvas.height) return;

const pixel = context.getImageData(x, y, 1, 1).data;
if (pixel[3] === 0) {
  setHoveredUV(uv);

  // Replace transparent area with tile texture
  const tileLoader = new THREE.TextureLoader();
  tileLoader.load(tileTexture, (tile) => {
    const material = new THREE.MeshBasicMaterial({
      map: tile,
      side: THREE.DoubleSide,
      transparent: true,
      blending: THREE.MultiplyBlending,
    });

    // Apply the material to the scene where transparency is detected (optional: modify geometry or mesh here)
    // Example: You can apply this to a cube geometry or any object you wish.
  });
} else {
  setHoveredUV(null);
}

};

useEffect(() => {
window.addEventListener(‘mousemove’, onMouseMove);
return () => {
window.removeEventListener(‘mousemove’, onMouseMove);
};
}, );

return (
<>
{hoveredUV && (
<div style={{ position: ‘absolute’, left: 10, top: 10 }}>
Hovering over transparent area at UV: {hoveredUV.x.toFixed(2)}, {hoveredUV.y.toFixed(2)}

)}
</>
);
};

export default PanoramaViewer;
import React from ‘react’;
import { Canvas } from ‘@react-three/fiber’;
import { OrbitControls } from ‘@react-three/drei’;
import PanoramaViewer from ‘./components/PanoramaViewer’;

// Import the images for the skybox and texture tile
import py from ‘./assets/py.png’;
import px from ‘./assets/px.png’;
import pz from ‘./assets/pz.png’;
import ny from ‘./assets/ny.png’;
import nx from ‘./assets/nx.png’;
import nz from ‘./assets/nz.png’;
import tile from ‘./assets/tile.jpg’; // Tile texture for transparent areas

const App: React.FC = () => {
const cubeImages = [px, nx, py, ny, pz, nz]; // 360° cube images

return (
<div style={{ width: ‘100vw’, height: ‘100vh’ }}>


<pointLight position={[10, 10, 10]} />

    {/* 360 Panorama Viewer with tile texture */}
    <PanoramaViewer cubeImages={cubeImages} tileTexture={tile} />

    {/* Controls to look around */}
    <OrbitControls enableZoom={true} />
  </Canvas>
</div>

);
};

export default App;

Create sphere with the transparent 360 texture - then create a slightly bigger sphere with the tile texture behind it. Issue gets a little more complicated if you want to replace multiple textures, but will just come down to trimming the larger sphere geometry to specific region only.

I have applied the tile texture in the 360° view, but the issue is that the texture is also being applied to the room objects. I only want the tile texture to be applied to the transparent floor or walls.

import React, { useEffect, useState } from 'react';
import { useThree, useLoader } from '@react-three/fiber';
import { TextureLoader } from 'three';
import * as THREE from 'three';

interface PanoramaViewerProps {
  cubeImages: string[];
  tilesData: Array<{ imgUrl: string[] }>;
  wallData: Array<WallData>;
}

export interface WallData {
  width: number;
  name: string;
  height: number;
  positionX: number;
  positionY: number;
  positionZ: number;
  rotationY: number;
  rotateX: number;
  face: string;
  textureUrl: string;
}

const PanoramaViewer: React.FC<PanoramaViewerProps> = ({ cubeImages, tilesData, wallData }) => {
  const { scene } = useThree();
  const [hoveredWall, setHoveredWall] = useState<THREE.Mesh | null>(null);
  const raycaster = new THREE.Raycaster();
  const mouse = new THREE.Vector2();

  // Load wall textures
  const wallTextures = useLoader(TextureLoader, wallData.map((wall) => wall.textureUrl));

  useEffect(() => {
    const loader = new THREE.CubeTextureLoader();
    const cubeTexture = loader.load(cubeImages);
    scene.background = cubeTexture;
  }, [cubeImages, scene]);

  // Create walls and floor in the scene
  useEffect(() => {
    wallData.forEach((wall, index) => {
      const wallGeometry = new THREE.PlaneGeometry(wall.width, wall.height);

      // Determine if the wall is transparent (like the floor)
      const isTransparentWall = wall.face === "floor"; // Adjust condition as necessary

      const wallMaterial = new THREE.MeshStandardMaterial({
        map: isTransparentWall ? wallTextures[index] : null, // Only apply texture if wall is transparent
        side: THREE.DoubleSide,
        transparent: isTransparentWall, // Set transparency based on wall type
        opacity: isTransparentWall ? 0.5 : 1.0, // Adjust opacity based on wall type
      });

      const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
      wallMesh.position.set(wall.positionX, wall.positionY, wall.positionZ);
      wallMesh.rotation.y = wall.rotationY;
      wallMesh.rotation.x = wall.rotateX;

      wallMesh.name = wall.face; // Set name based on face type
      scene.add(wallMesh);

      // Check if this is the floor and apply tile texture if needed
      if (isTransparentWall) {
        const tileTexture = new THREE.TextureLoader().load(tilesData[0].imgUrl[0], (texture) => {
          texture.wrapS = THREE.RepeatWrapping;
          texture.wrapT = THREE.RepeatWrapping;


          wallMesh.material.map = texture; // Apply texture to the floor material
          wallMesh.material.transparent = true; // Ensure transparency is enabled
          wallMesh.material.opacity = 0.5; // Maintain transparency
          wallMesh.material.needsUpdate = true; // Ensure the material updates
        });
      }
    });
  }, [wallData, wallTextures, scene, tilesData]);

  // Mouse click handler for applying tile texture
  function onMouseClick(event: MouseEvent) {
    if (hoveredWall && hoveredWall.name === "floor") { // Only apply texture if hovered wall is the floor
      const randomIndex = Math.floor(Math.random() * tilesData.length);
      const selectedTile = tilesData[randomIndex];

      loadImage(selectedTile.imgUrl[0]).then((image) => {
        const texture = new THREE.Texture(image);
        texture.needsUpdate = true;
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;

        // Apply the tile texture only to the hovered transparent wall (floor)
        const material = hoveredWall.material as THREE.MeshStandardMaterial;
        material.map = texture; // Apply tile texture
        material.transparent = true; // Ensure transparency is enabled
        // material.opacity = 0.5; // Maintain transparency
        material.needsUpdate = true; // Ensure the material updates
      });
    }
  }

  useEffect(() => {
    window.addEventListener('click', onMouseClick);

    return () => {
      window.removeEventListener('click', onMouseClick);
    };
  }, [hoveredWall, tilesData]);

  // Helper function to load images
  const loadImage = (url: string): Promise<HTMLImageElement> => {
    return new Promise((resolve, reject) => {
      const image = new Image();
      image.src = url;
      image.onload = () => resolve(image);
      image.onerror = (error) => reject(error);
    });
  };

  return null; // Render null since we are using a 3D scene
};

export default PanoramaViewer;

Well, the code you’ve shared doesn’t seem to follow the suggested solution above so that answer kinda still applies :sweat_smile: You need two overlapping surfaces - one with the umasked non-colorable objects, and one behind that applies configurable textures / colors to the masked objects.

My 360-degree view, featuring six cube images, is now functioning perfectly. In this view, the tile texture is correctly positioned on the transparent wall, but I’m having trouble setting the proper coordinates.`import React, { useEffect, useRef } from “react”;
import * as THREE from “three”;
import { OrbitControls } from “three/examples/jsm/controls/OrbitControls.js”;
import front from “…/assets/front.png”;
import back from “…/assets/back.png”;
import top from “…/assets/top.png”;
import bottom from “…/assets/bottom.png”;
import left from “…/assets/left.png”;
import right from “…/assets/right.png”;

const ThreeScene: React.FC = () => {
const containerRef = useRef(null);
const raycaster = new THREE.Raycaster();

var informazione = {
    floor_tile_width: 8,
    floor_tile_height: 12,
    wall_tile_width: 6,
    wall_tile_height: 6,
};

useEffect(() => {
    const renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0xffffff, 1);

    if (containerRef.current) {
        containerRef.current.appendChild(renderer.domElement);
    }

    const scene = new THREE.Scene();

    const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
    );
    camera.position.z = 0.01;

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableZoom = false;
    controls.enablePan = false;
    controls.enableDamping = true;
    controls.rotateSpeed = -0.5; // Slower rotation for finer control


    const textures: THREE.Texture[] = [];

    const transparentImageUrls = [left, right, top, bottom, back, front];

    const textureLoader = new THREE.TextureLoader();
    transparentImageUrls.forEach((url) => {
        const texture = textureLoader.load(url);
        texture.colorSpace = THREE.SRGBColorSpace;

        textures.push(texture);
    });

    const materials: any = [];
    for (let i = 0; i < 6; i++) {
        materials.push(new THREE.MeshBasicMaterial({ map: textures[i], transparent: true }));
    }

    const skyBox = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), materials);
    skyBox.geometry.scale(1, 1, -1);
    scene.add(skyBox);

    // Floor setup
    const floorGeometry = new THREE.PlaneGeometry(
        informazione.floor_tile_width,
        informazione.floor_tile_height
    );
    const floorMaterial = new THREE.MeshBasicMaterial({
        color: 0xffffff,
        side: THREE.DoubleSide,
        transparent: true,
        opacity: 0,
    });
    const floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
    floorMesh.name = "Floor";
    floorMesh.position.y = -1.01;
    floorMesh.rotation.x = -Math.PI / 2;
    scene.add(floorMesh);

    // Wall 1
    const wall1Geometry = new THREE.PlaneGeometry(
        informazione.wall_tile_width,
        informazione.wall_tile_height
    );
    const wall1Material = new THREE.MeshBasicMaterial({
        color: 0xffffff,
        transparent: true,
        opacity: 0,
    });
    const wall1Mesh = new THREE.Mesh(wall1Geometry, wall1Material);
    wall1Mesh.name = "Wall1";
    wall1Mesh.position.set(1, -1, 1);
    wall1Mesh.rotation.x = -(Math.PI / 180) * 180;
    scene.add(wall1Mesh);

    // Wall 2
    const wall2Geometry = new THREE.PlaneGeometry(
        informazione.wall_tile_width,
        informazione.wall_tile_height
    );
    const wall2Material = new THREE.MeshBasicMaterial({
        color: 0xffffff,
        transparent: true,
        opacity: 0,
    });
    const wall2Mesh = new THREE.Mesh(wall2Geometry, wall2Material);
    wall2Mesh.name = "Wall2";
    wall2Mesh.position.set(75, 0, 75);
    wall2Mesh.rotation.y = -Math.PI;
    scene.add(wall2Mesh);

    // Wall 3
    const wall3Geometry = new THREE.PlaneGeometry(
        informazione.wall_tile_width,
        informazione.wall_tile_height
    );
    const wall3Material = new THREE.MeshBasicMaterial({
        color: 0xffffff,
        transparent: true,
        opacity: 0,
    });
    const wall3Mesh = new THREE.Mesh(wall3Geometry, wall3Material);
    wall3Mesh.name = "Wall3";
    wall3Mesh.position.set(2, 5, 10);
    wall3Mesh.rotation.y = -Math.PI;
    scene.add(wall3Mesh);

    function onMouseClick(event: MouseEvent) {
        const mouse = new THREE.Vector2();
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

        const textureLoader = new THREE.TextureLoader();
        raycaster.setFromCamera(mouse, camera);

        const intersects = raycaster.intersectObjects(scene.children, true);

        if (intersects.length > 0) {
            const floorIntersect = intersects.find(
                (intersection) => intersection.object.name === "Floor"
            );
            if (floorIntersect && floorIntersect.object instanceof THREE.Mesh) {
                const floorTexture = textureLoader.load(
                    "https://res.cloudinary.com/ecommerceapi/image/upload/v1713678490/LivingRoom/FloorTiles/2.webp"
                );
                floorTexture.colorSpace = THREE.SRGBColorSpace;
                floorTexture.wrapS = THREE.RepeatWrapping;
                floorTexture.wrapT = THREE.RepeatWrapping;
                floorTexture.repeat.set(4, 4);

                const floorMaterial = new THREE.MeshBasicMaterial({
                    map: floorTexture,
                    transparent: true,
                    opacity: 1,
                });
                floorIntersect.object.material = floorMaterial;
            }

            const wall1Intersect = intersects.find(
                (intersection) => intersection.object.name === "Wall1"
            );
            if (wall1Intersect && wall1Intersect.object instanceof THREE.Mesh) {
                const wallTexture = textureLoader.load(
                    "https://res.cloudinary.com/ecommerceapi/image/upload/v1713678490/LivingRoom/FloorTiles/1.webp"
                );
                wallTexture.colorSpace = THREE.SRGBColorSpace;
                wallTexture.wrapS = THREE.RepeatWrapping;
                wallTexture.wrapT = THREE.RepeatWrapping;
                wallTexture.repeat.set(2, 2);

                const wallMaterial = new THREE.MeshBasicMaterial({
                    map: wallTexture,
                    transparent: true,
                    opacity: 1,
                });
                wall1Intersect.object.material = wallMaterial;
            }

            const wall2Intersect = intersects.find(
                (intersection) => intersection.object.name === "Wall2"
            );
            if (wall2Intersect && wall2Intersect.object instanceof THREE.Mesh) {
                const wallTexture = textureLoader.load(
                    "https://res.cloudinary.com/ecommerceapi/image/upload/v1713678490/LivingRoom/FloorTiles/1.webp"
                );
                wallTexture.colorSpace = THREE.SRGBColorSpace;
                wallTexture.wrapS = THREE.RepeatWrapping;
                wallTexture.wrapT = THREE.RepeatWrapping;
                wallTexture.repeat.set(8, 8);

                const wallMaterial = new THREE.MeshBasicMaterial({
                    map: wallTexture,
                    transparent: true,
                    opacity: 1,
                });
                wall2Intersect.object.material = wallMaterial;
            }
        }
    }

    window.addEventListener("click", onMouseClick);

    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    }

    animate();

    return () => {
        window.removeEventListener("click", onMouseClick);
        if (containerRef.current) {
            containerRef.current.removeChild(renderer.domElement);
        }
    };
}, []);

return <div ref={containerRef} />;

};

export default ThreeScene;
`