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.