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();
      // resource URL
      // 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);
        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)
          // test axis for indicator placer
          // {x: 403.485721, y: 1454.024825}
         renderer = new THREE.WebGLRenderer({
        //  renderer.setPixelRatio( window.devicePixelRatio );
         renderer.setSize(width, height)
         // scene.background = new THREE.Color( 0xe0dddd );
         // camera
         camera = new THREE.PerspectiveCamera(
         canvas.clientWidth / canvas.clientHeight,
         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
            // render()

          const getZoomVal = () => {
            return  100 - controls.distance;
          let _zVal = getZoomVal()
          function animate() {
            _zVal = getZoomVal();
            const delta = clock.getDelta()
            // handle zoom button click
              controls.dolly(Math.pow( 7.95, controls.dollySpeed),true)
              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.setTarget(window.lookAxis.x, window.lookAxis.y, 0, true)


          function render() { 
            renderer.render(scene, camera)

         const _edge = fitCameraToCenteredObject(camera, gltf.scene, undefined, controls)
          controls.maxDistance = _edge.cameraToFarEdge * 2
            /* */
        }, 100);

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

above is what my code looks like so far

Oh, all right. Then use a 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} ) );

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.