I'd like to implement transformcontrol threejs in mapbox. First I add cube to the scene and attach it to the control. In current mapbox I have some other layer, Icon, 3d building etc. The problem is I can't hover transformcontrol threejs correctly and can't move the cube.
Seems this happened because layer of mapbox.

export class ModelLayerAOA implements mapboxgl.CustomLayerInterface {
modelOrigin: [number, number];
modelAltitude: number;
onLoad?: () => void;
id: string;
type: 'custom';
renderingMode: '3d';
modelTransform: {
translateX: number;
translateY: number;
translateZ: number;
rotateX: number;
rotateY: number;
rotateZ: number;
scale: number;
};
color: number;
map: mapboxgl.Map | undefined;
camera: THREE.PerspectiveCamera | undefined;
scene: THREE.Scene | undefined;
renderer: THREE.WebGLRenderer | undefined;
model: THREE.Group | undefined | THREE.Mesh;
transformControl: TransformControls | undefined;
constructor(options: SpriteOption) {
this.modelOrigin = options.origin;
this.modelAltitude = options.altitude;
this.onLoad = options.onLoad;
this.id = options.id;
this.type = 'custom';
this.renderingMode = '3d';
this.color = options.color;
const rotate = [Math.PI / 2, THREE.MathUtils.degToRad(options.rotateY), 0];
const mercator = mapboxgl.MercatorCoordinate.fromLngLat(
this.modelOrigin,
this.modelAltitude,
);
const coord = new mapboxgl.MercatorCoordinate(
mercator.x,
mercator.y,
mercator.z,
);
console.log(mercator);
console.log(coord.toLngLat());
const scale = mercator.meterInMercatorCoordinateUnits();
this.modelTransform = {
translateX: mercator.x,
translateY: mercator.y,
translateZ: mercator.z ?? 0,
rotateX: rotate[0],
rotateY: rotate[1],
rotateZ: rotate[2],
scale,
};
}
async onAdd(map: mapboxgl.Map, gl: WebGLRenderingContext) {
this.map = map;
this.camera = new THREE.PerspectiveCamera(75);
this.camera.position.z = 1;
this.scene = new THREE.Scene();
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
this.scene.add(ambientLight);
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
transparent: true,
opacity: 0.3,
});
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true,
});
if (this.renderer?.domElement && this.camera) {
this.transformControl = new TransformControls(
this.camera,
this.renderer?.domElement,
);
this.transformControl.size = 5;
this.transformControl.addEventListener('change', this.updateRender);
}
const cube = new THREE.Mesh(geometry, material);
let pos = new THREE.Vector3();
cube.getWorldPosition(pos);
this.model = cube;
this.renderer.autoClear = false;
this.addTransformControl();
}
addTransformControl = () => {
if (this.transformControl && this.model) {
this.transformControl?.attach(this.model);
this.scene?.add(this.transformControl);
this.scene?.add(this.model);
}
};
onRemove(map: mapboxgl.Map) {
map.removeLayer(this.id);
if (this.model) {
this.scene?.remove(this.model);
}
this.camera?.clear();
this.scene?.clear();
}
render(gl: WebGLRenderingContext, matrix: number[]) {
const modelTransform = this.modelTransform;
const rotationX = new THREE.Matrix4().makeRotationAxis(
new Vector3(1, 0, 0),
modelTransform.rotateX,
);
const rotationY = new THREE.Matrix4().makeRotationAxis(
new Vector3(0, 1, 0),
modelTransform.rotateY,
);
const rotationZ = new THREE.Matrix4().makeRotationAxis(
new Vector3(0, 0, 1),
modelTransform.rotateZ,
);
const m = new THREE.Matrix4().fromArray(matrix);
const l = new THREE.Matrix4()
.makeTranslation(
modelTransform.translateX,
modelTransform.translateY,
modelTransform.translateZ,
)
.scale(
new Vector3(
modelTransform.scale,
-modelTransform.scale,
modelTransform.scale,
),
)
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
if (this.camera && this.scene && this.map) {
this.camera.projectionMatrix.elements = matrix;
this.camera.projectionMatrix = m.multiply(l);
this.renderer?.resetState();
this.updateRender();
this.map.triggerRepaint();
}
}
updateRender = () => {
if (this.scene && this.camera) {
this.renderer?.render(this.scene, this.camera);
}
};
}