Reputation: 475
So, I have run into an issue using RayCaster
to pick up TextGeometry
. I am using the function createText()
below to render this text onto the canvas. This works fine, it shows up, and it even adds it to the array of meshes for the RayCaster
it check for intersection, however, the function HandleSingleClick()
is not firing on TextGeometries for some reason.
I have tested using cubes, and it does work. The intention is that if you click on the TextGeometry, it changes color to denote that you clicked on it. However, for some reason, the following script doesn't work when it comes to Text. I can confirm that the meshes are being added to the array the RayCaster checks in, but it doesn't pick them up for some reason.
import {
Font,
TextGeometry
} from '../js/libs/Three.es.js';
import FontJson from '../fonts/helvetiker_bold.typeface.json';
export default class TextExtension extends Autodesk.Viewing.Extension {
constructor(viewer, options) {
super()
this.viewer = viewer
}
load() {
console.log('Viewing.Extension.MeshSelection loaded')
this.viewer.addEventListener(
Autodesk.Viewing.OBJECT_TREE_CREATED_EVENT, () => {
this.dbIds = this.getAllDbIds()
console.log(this.dbIds);
});
this.viewer.toolController.registerTool(this)
this.viewer.toolController.activateTool(
'MeshSelection')
this.intersectMeshes = [];
return true
}
/////////////////////////////////////////////////////////
// Tool Interface
//
/////////////////////////////////////////////////////////
getNames() {
return ['MeshSelection']
}
activate() {
}
deactivate() {
}
/////////////////////////////////////////////////////////
// Unload callback
//
/////////////////////////////////////////////////////////
unload() {
console.log('MeshSelection unloaded')
this.viewer.toolController.deactivateTool(
'MeshSelection')
this.viewer.toolController.unregisterTool(this)
return true
}
/////////////////////////////////////////////////////////
// Adds a box mesh with random size and position
// to the scene
//
/////////////////////////////////////////////////////////
addMesh() {
const geometry = new THREE.BoxGeometry(
Math.random() * 10 + 5.0,
Math.random() * 10 + 5.0,
Math.random() * 10 + 5.0)
const color = Math.floor(Math.random() * 16777215)
const material = this.createColorMaterial(color)
const mesh = new THREE.Mesh(geometry, material)
mesh.position.x = -50 + Math.random() * 25
mesh.position.y = -50 + Math.random() * 25
mesh.position.z = 1 + Math.random() * 1
this.viewer.impl.scene.add(mesh)
this.viewer.impl.sceneUpdated(true)
return mesh
}
/////////////////////////////////////////////////////////
// Creates color material from int
//
/////////////////////////////////////////////////////////
createColorMaterial(color) {
const material = new THREE.MeshPhongMaterial({
specular: new THREE.Color(color),
side: THREE.DoubleSide,
reflectivity: 0.0,
color
})
const materials = this.viewer.impl.getMaterials()
materials.addMaterial(
color.toString(16),
material,
true)
return material
}
/////////////////////////////////////////////////////////
// Creates Raycaster object from the pointer
//
/////////////////////////////////////////////////////////
pointerToRaycaster(domElement, camera, pointer) {
const pointerVector = new THREE.Vector3()
const pointerDir = new THREE.Vector3()
const ray = new THREE.Raycaster()
const rect = domElement.getBoundingClientRect()
const x = ((pointer.clientX - rect.left) / rect.width) * 2 - 1
const y = -((pointer.clientY - rect.top) / rect.height) * 2 + 1
if (camera.isPerspective) {
pointerVector.set(x, y, 0.5)
pointerVector.unproject(camera)
ray.set(camera.position,
pointerVector.sub(
camera.position).normalize())
} else {
pointerVector.set(x, y, -1)
pointerVector.unproject(camera)
pointerDir.set(0, 0, -1)
ray.set(pointerVector,
pointerDir.transformDirection(
camera.matrixWorld))
}
return ray
}
/////////////////////////////////////////////////////////
// Click handler
//
/////////////////////////////////////////////////////////
handleSingleClick(event) {
console.log(this.intersectMeshes);
const pointer = event.pointers ?
event.pointers[0] :
event
console.log(pointer);
const rayCaster = this.pointerToRaycaster(
this.viewer.impl.canvas,
this.viewer.impl.camera,
pointer)
const intersectResults = rayCaster.intersectObjects(
this.intersectMeshes, true)
console.log(intersectResults);
const hitTest = this.viewer.model.rayIntersect(
rayCaster, true, this.dbIds)
const selections = intersectResults.filter((res) =>
(!hitTest || (hitTest.distance > res.distance))
)
if (selections.length) {
console.log('Custom meshes selected:')
console.log(selections)
selections[0].object.material.color = this.createColorMaterial(Math.floor(Math.random() * 16777215));
viewer.impl.sceneUpdated(true);
return true
}
return false
}
/////////////////////////////////////////////////////////
// Get list of all dbIds in the model
//
/////////////////////////////////////////////////////////
getAllDbIds() {
const {
instanceTree
} = this.viewer.model.getData()
const {
dbIdToIndex
} = instanceTree.nodeAccess
return Object.keys(dbIdToIndex).map((dbId) => {
return parseInt(dbId)
})
}
createColorMaterial(color) {
const material = new THREE.MeshPhongMaterial({
specular: new THREE.Color(color),
side: THREE.DoubleSide,
reflectivity: 0.0,
color
})
const materials = this.viewer.impl.getMaterials()
materials.addMaterial(
color.toString(),
material,
true)
return material
}
/////////////////////////////////////////////////////////
// Wraps TextGeometry object and adds a new mesh to
// the scene
/////////////////////////////////////////////////////////
createText(params, index) {
const geometry = new TextGeometry(params.text,
Object.assign({}, {
font: new Font(FontJson),
params
}))
geometry.computeBoundingBox();
const material = this.createColorMaterial(
params.color)
const text = new THREE.Mesh(
geometry, material)
text.scale.set(params.scale, params.scale, params.scale);
text.position.set(
params.position.x,
params.position.y,
10)
this.intersectMeshes[index] = text;
this.viewer.impl.scene.add(text);
this.viewer.impl.sceneUpdated(true)
}
}
Autodesk.Viewing.theExtensionManager.registerExtension(
'TextSpawner', TextExtension);
Upvotes: 2
Views: 557
Reputation: 4375
You need to debug the ray casting logic to find out what is going on. In the Three.js version that the viewer is using there is a chech to see if the geometry object from the tested mesh is of instance THREE.BufferGeometry or THREE.Geometry, if none the intersection logic is not computed.
In order to make it compatible with it while adding as little code as possible, I used the following approach:
/////////////////////////////////////////////////////////
// Wraps TextGeometry object and adds a new mesh to
// the scene
/////////////////////////////////////////////////////////
createText (params) {
const textGeometry = new TextGeometry(params.text,
Object.assign({}, {
font: new Font(FontJson),
params
}))
// use a geometry recognized by the viewer
// THREE.js version
const geometry = new THREE.BufferGeometry
geometry.fromGeometry(textGeometry)
const material = this.createColorMaterial(
params.color)
const text = new THREE.Mesh(
geometry , material)
text.position.set(
params.position.x,
params.position.y,
params.position.z)
this.viewer.impl.scene.add(text)
this.viewer.impl.sceneUpdated(true)
return text
}
Upvotes: 1