Image placement on custom x and y coordinate

i want to place a custom image(an indicator) on different x and y coordinates of a loaded glb file.
please am new to three js , I woul appreciate any assistance

You will need 3 coordinates to place the image (x, y and z).

You can place the image by using THREE.Sprite class. Look at this example on how to create sprites:

Then, once you have created the sprite with the texture (the image), just set its position:
mySprite.position.set( x, y, z );

And add it to the glb model:
myGLBModel.add( mySprite );

The position (x, y, z ) is relative to the origin of the model (its pivot point).

Happy coding.

Ok thank you very much @yombo , will implement it today
please another question, the source that gives me the coordinates has only x and y coordinates, i dont know if i can manually calculate the value for the z-axis

Just try z = 0. Then you can adjust it so that it looks the way you want.

yeah it worked
thank you @yombo
But it seems what i want to achieve is more complicated
the position of the sprite is static and has two issues

  • whenever i rotate the whole gltf model, the sprite doesnt rotate with it.
  • whenever i zoom it disappears somehow


the circled part is the sprite i added and i set the position to the position(x and y coordinate of the component it is on)


this is a video of how it behaves

@yombo i really appreciate your help
lemme explain clearly what i really want to achieve with the whole project … i have a glb model of an asset that contains different components as you can see from the image & video i shared , I also know the x and y coordinate of all its components , so i plan on looping on each of the components x and y coordinates then place an image(indicator) on top of the component and each of the placed indicator should rotate and behave as the model rather than staying static

 // scene
    scene = new THREE.Scene()

    // Load a glTF resource
    const loader = new GLTFLoader();
    loader.load(
      // resource URL
      `http://${location.host}/api/getGlb`,
      // called when the resource is loaded
      function ( gltf : any ) {
        var obj = gltf.scene
        obj.traverse( (o : any) => {
          if ((o as any).isMesh) {
            (o as any).material.wireframe = activeDisplay=="solid" ? false : true;
            // if(activeDisplay=="wireframe") (o as any).material = material
            
          }
        })
    
        scene.add( obj);
        setLoading(false)
       
        gltf.animations; // Array<THREE.AnimationClip>
        gltf.scene; // THREE.Group
        gltf.scenes; // Array<THREE.Group>
        gltf.cameras; // Array<THREE.Camera>
        gltf.asset; // Object

        setTimeout(() => {  
          // canvas
          canvas = document.getElementById('model') as any
          const height = canvas.clientHeight
          const width = canvas.clientWidth

          const texture = new THREE.TextureLoader().load('/logo.png')
          console.warn('loading texture',texture)
          const material = new THREE.SpriteMaterial( { map: texture } ) ;
          const sprite = new THREE.Sprite( material );
          console.warn('created sprite',sprite)
          sprite.scale.set(200,200,200)
          
          // test axis for indicator placer
          // {x: 403.485721, y: 1454.024825}
          sprite.position.set(403.485721,1454.024825,3)
          obj.add(sprite)
 
         renderer = new THREE.WebGLRenderer({
           canvas,
           antialias:true
         })
        //  renderer.setPixelRatio( window.devicePixelRatio );
         renderer.setSize(width, height)
         renderer.setClearColor(0xe0dddd);
 
         // scene.background = new THREE.Color( 0xe0dddd );
 
         // camera
         camera = new THREE.PerspectiveCamera(
         60,
         canvas.clientWidth / canvas.clientHeight,
         0.01,
         1000
         ) 
         camera.position.z = 400;
         const clock = new THREE.Clock();
         
         scene.add( camera );


        controls = new CameraControls( camera, renderer.domElement);
        controls.dollySpeed = 2;
        // controls.minDistance = 0
        // controls.maxDistance = 100
  

         const pointLight = new THREE.PointLight( 0xffffff, 0.8 );
         camera.add( pointLight );
 
         window.addEventListener('resize', onWindowResize)
 
          function onWindowResize() {
            renderer.setSize(canvas.clientWidth, canvas.clientHeight)
            camera.aspect = canvas.clientWidth / canvas.clientHeight
            camera.updateProjectionMatrix()
            // render()
          }

          const getZoomVal = () => {
            return  100 - controls.distance;
          }
          let _zVal = getZoomVal()
          function animate() {
            setZoomValue(getZoomVal())
            _zVal = getZoomVal();
            const delta = clock.getDelta()
            
            // handle zoom button click
            if(window.zoomIn){
              controls.dolly(Math.pow( 7.95, controls.dollySpeed),true)
            }
            if(window.zoomOut){
              controls.dolly(-Math.pow( 7.95, controls.dollySpeed),true)
            }
            if(externalControl) externalControl.setAngles(controls.polarAngle,controls.azimuthAngle)
            if(Object.keys(window.lookAxis).length>0) {
              controls.zoomTo(7,true)
              controls.setTarget(window.lookAxis.x, window.lookAxis.y, 0, true)

              controls.update(clock.getDelta())
              setLookAxis({show:false,x:0,y:0})
            }

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

         const _edge = fitCameraToCenteredObject(camera, gltf.scene, undefined, controls)
          controls.fitToBox(obj,true)
          controls.maxDistance = _edge.cameraToFarEdge * 2
          controls.update(clock.getDelta())
          animate()
            /* */
        }, 100);

      },
      // called while loading is progressing
      function ( xhr : any ) {
        setLoading(true)
        console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
      },
      // called when loading has errors
      function ( error : any ) {
        console.log( 'An error happened',error );
        setLoading(false)
        setErr(true)
      }
    );

above is what my code looks like so far

Oh, all right. Then use a PlaneGeometry:
https://threejs.org/docs/index.html?q=planeg#api/en/geometries/PlaneGeometry

Give it a MeshBasicMaterial with a map (the image), that’s all.

Thank you @yombo
it worked

A quick one
i added a sphereGeometry on the position i wanted but the sphere geometry keeps clipping and its control behaviour does not behave wellas the component
I dont know if its because am setting the z position of the sphere to 0 because it is unknown?

var indicator = new THREE.Mesh( new THREE.SphereGeometry(0.8),new THREE.MeshBasicMaterial( {color: 0xff0000} ) );
          indicator.scale.set(70,70,70)
          indicator.position.set(403.485721,1454.024825,0)
          obj.add(indicator)

where obj is my glb model

See The behaviour below

Note: what i want to achieve is

Sorry for the delay.

Please try: indicator.material.depthTest = false;

This will make the red sphere to not be occluded by the rest of geometry.