I want to be able to select individual model elements in Playcanvas modelviewer, change their texture and show relative metadata. The problem is that I can not use raycastFirst method to find target element, because rigidbody is undefined. This is what i tried:
app.mouse.on(EVENT_MOUSEDOWN, function (event) {
var from = this.camera.camera.screenToWorld(event.x, event.y, this.camera.camera.nearClip);
var to = this.camera.camera.screenToWorld(event.x, event.y, this.camera.camera.farClip);
var result = app.systems.rigidbody.raycastFirst(from, to);
// goes on
}, this);
app.mouse.attach(canvas);
And this is the error I get:
TypeError: Cannot read properties of undefined (reading ‘raycastFirst’)
So, in modelviewer rigidbody is undefined on app.systems. What is wrong with that and how can we fix it?
Hello, @will Will! No, I did not. By the way, I found some relatively working solution, which is based on finding intersection with elements bbox:
app.mouse.on(EVENT_MOUSEUP, (event) => {
const pos = new Vec2(event.x, event.y);
const ray = new Ray();
this.camera.camera.screenToWorld(pos.x, pos.y, this.camera.camera.nearClip, ray.origin);
this.camera.camera.screenToWorld(pos.x, pos.y, this.camera.camera.farClip, ray.direction);
ray.direction.sub(ray.origin).normalize();
let selectedEntity = null;
let minDistance = Number.MAX_VALUE;
const entity = window.viewer.entities[0] as Entity;
const components = entity.findComponents('render');
for (let i = 0; i < components.length; i++) {
const render = components[i] as RenderComponent;
if (render.meshInstances) {
var aabb = render.meshInstances[0].aabb;
const intersectionPoint = new Vec3();
if (aabb.intersectsRay(ray, intersectionPoint)) {
const distance = intersectionPoint.sub(ray.origin).length();
if (render.entity.enabled && distance < minDistance) {
minDistance = distance;
selectedEntity = render.entity;
}
}
}
}
//goes on
});
But sometimes it works incorrectly - not mathematically, but from user point of view. For example, imagine some wall with a niche and a door, if a user clicks on the door, we indeed expect to select this door, but unfortunatelly door bbox may be iside this wall bbox and so, the whole wall is selected. So, itersecting with bbox is good, but not perfect. I wish there was a better solution
Yeah, that is a problem with that approach. You could split wall sections into convex parts, potentially. But that might be a lot of work, depending on your assets.
If you don’t have a large number of triangles in your scene objects, you could use bboxes to identify the potential meshes selected and then iterate over the triangles of those mesh instances and do tri/ray intersections:
Then figure out which intersection point is closest to the camera. Not optimal, but it should work!
Hi, @will Will! I managed to create additional convex meshes in my model, that start from UCX_ prefix, intended for later use in Unreal Engine. And now I want to create a rigid body from them in Playcanvas viewer, so that I could interect with individual elements, that have these collisions. So, my question is how to create such a rigid body from these convex meshes (or just from any mesh) in Playcanvas viewer, that I use as a preview before loading my model to Unreal Engine project. Thanks in advance!
Hi, @will Will! Yes, I mean this model viewer. What I’m doing is uploading a model with collision meshes, starting from UCX_ (for compatibility with Unreal Engine, what in fact is not so important). And what I want is to create rigid bodies from these very meshes (those starting from UCX_). I need this in order to implement another extra functionality in Playcanvas model viewer - that is selecting specific meshes of the uploaded model. The catch is, I’m following some naming conventions and my collision meshes share the same name with ordinary meshes. Ordinary meshes are named like “blabla” and collision meshes are named like “UCX_blabla”.
So, the whole problem at this moment - is how to create collisions from specific meshes in Playcanvas model viewer.