How do you implement drag controls in the AutoDesk forge viewer? - javascript

I am trying to implement drag controls on this text geometry that I am creating in the viewer. I create the text like so:
createText(params) {
const textGeometry = new TextGeometry(params.text,
Object.assign({}, {
font: new Font(FontJson),
params
}));
const geometry = new THREE.BufferGeometry;
geometry.fromGeometry(textGeometry);
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.push(text);
this.viewer.impl.scene.add(text);
this.viewer.impl.sceneUpdated(true);
return text;
}
This works great, the meshes get added to the viewer, I can see them. Fantastic! Thus far, it is good. Now, I want to be able to drag them around with my mouse after I have added them. I noticed that Three.js already has drag controls built in, so I just implemented them like so:
enableDragging(){
let controls = new THREE.DragControls( this.viewer, this.viewer.impl.camera.perspectiveCamera, this.viewer.impl.canvas );
controls.addEventListener( 'dragstart', dragStartCallback );
let startColor;
controls.addEventListener( 'dragend', dragendCallback );
function dragStartCallback(event) {
startColor = event.object.material.color.getHex();
event.object.material.color.setHex(0x000000);
}
function dragendCallback(event) {
event.object.material.color.setColor(startColor);
}
}
After a big of debugging, I have seen where the problem occurs. For some reason, when I click on one of the meshes, the raycaster doesn't find any intersections. I.E. the array I get back is empty. No matter where I click on these objects.
Is my implementation wrong, or did I provision these meshes wrong to make them draggable? I have gotten the drag controls to work outside of the viewer, just not within it.

This will not work, looking at the code of DragControls, the viewer implementation is too different in the way it implements the camera. You would need to either implement a custom version of DragControls or take a look at my transform tool and adapt it for custom meshes:
Moving visually your components in the viewer using the TransformTool

Related

Does have instagram masks specified UI to chage the 3d objects instead changing textures only?

So i have 3 different, which contains different 3d objects with special animations.
First is 3d objects rotating above the head and change the angle of orbit with our head shakes. The second one is falling 2d sprites all around character calling by eye closing. And the third one is simple facemesh with grid texture on it. Im draw special UI and code it, so in ArPlayer it works perfects, but when im try to upload it to facebook this UI not working and i have only mask number 1.
So im try to search the solution on Youtube and have only this, but this works only with texture changing i think. So my question is: Can i use instagram changing ui with my effects and if yes, how i can do this. Thaks a lot!
P.S: All images u can find.
Effects must not use custom buttons, keyboards, pickers or sliders - effects may use the native UI picker and slider only. (Spark AR Review Policies 2.6)
Using the Native UI picker, you can not only change textures, but also the visibility of objects.
Example:
Create a new project
Create several plane objects on the scene (for example 3 pieces) and name them obj0,
obj1, obj2 and make them invisible
In Capabilities add Native UI -> Picker
Add 3 textures to the project and name them icon_1, icon_2, icon_3 and check the "No compression" option for everyone
Add such a script
const NativeUI = require('NativeUI');
const Textures = require('Textures');
const Scene = require('Scene');
Promise.all([
Textures.findFirst('icon_1'),
Textures.findFirst('icon_2'),
Textures.findFirst('icon_3'),
Scene.root.findFirst('obj0'),
Scene.root.findFirst('obj1'),
Scene.root.findFirst('obj2')
]).then(onReady);
function onReady(assets) {
const texture0 = assets[0];
const texture1 = assets[1];
const texture2 = assets[2];
const objects = [assets[3],assets[4],assets[5]];
const picker = NativeUI.picker;
const index = 0;
const configuration = {
selectedIndex: index,
items: [
{image_texture: texture0},
{image_texture: texture1},
{image_texture: texture2}
]
};
picker.configure(configuration);
picker.visible = true;
picker.selectedIndex.monitor({fireOnInitialValue:true}).subscribe(function(index) {
objects[index.newValue].hidden = false;
if(index.oldValue != undefined)
{
objects[index.oldValue].hidden = true;
}
});
}
A similar official example is from developers, there they used Native UI picker (script) + patch to hide objects. Launch Spark AR Studio and create new project from template "3D Stickers" and watch how they did it. If you don’t have such a project template, update Spark AR Studio.

I want to add a hotspot to certain parts of the obj extension model I have installed with three.js. how can I do it?

I can add a click event to the model I loaded with Three.js, but I can't add a click event to a particular part of the model I've uploaded. For example, I can make a click event on the car model I have installed, but what I want to do is exactly this: when I click on the wheel of the car I want to write 'wheel' to the console. When I click on the glass I want to write 'glass'.
How can I do it?
const objLoader = new THREE.OBJLoader2();
objLoader.loadMtl('bugatti.mtl', null, (materials) => {
objLoader.setMaterials(materials);
objLoader.load('bugatti.obj', (event) => {
const root = event.detail.loaderRootNode;
scene.add(root);
myModel = root;
const domEvents = new THREEx.DomEvents(camera, renderer.domElement)
domEvents.addEventListener(myModel, 'click', event => {
console.log("car");
});
It's best to solve this issue during the design phase and ensure that your model does consist of multiple independent meshes grouped together to a more complex object. In this way, it will be much easier to select single components in three.js (and any other 3D engine).

Babylon.js OnIntersectionEnterTrigger not triggering with camera

I'm using Babylon.js 2.4.0.
I have a mesh (in the shape of a couch) loaded from a .obj file, and a camera set up like this:
let camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 2, 0), scene);
camera.checkCollisions = true;
camera.applyGravity = true;
camera.ellipsoid = new BABYLON.Vector3(1, 1, 1);
camera.attachControl(canvas, false);
camera.speed = 0.5;
camera.actionManager = new BABYLON.ActionManager(scene);
I want to set up an event so that when I walk through the couch, "intersection" is logged to the console:
let action = new BABYLON.ExecuteCodeAction(
{ trigger: BABYLON.ActionManager.OnIntersectionEnterTrigger, parameter: { mesh: couchMesh }},
(evt) => {
console.log("intersection");
}
);
this.camera.actionManager.registerAction(action);
When I walk through the mesh, nothing is logged to the console.
I've created an example on the Babylon.js Playground using an example that they provide to check that it wasn't a problem with my mesh or camera set up, and it doesn't appear to be (the playground doesn't work either).
A camera in Babylon.js has no action manager, so even if you set one it won't really work.
To get this to work using action managers, you could define an invisible box around the camera, with a predefined size and attach the action manager to the mesh created. then set the mesh's parent to be the camera, and you are done. Here is your playground with those changes - http://www.babylonjs-playground.com/#KNXZF#3
Another solution is to use the internal collision system of babylon js, and set the camera's onCollide function to actually do something :) Here is en example - http://www.babylonjs-playground.com/#KNXZF#4
Notice that in the second playground, the camera won't go throug the box, as the collision system prevents it from doing so. I am not sure about your usecase, so it is hard to say which one of the two will work better.
If you need a "gate" system (knowing when a player moved through a gate, for example), use the 1st method. The 2nd is much cleaner, but has its downsides.

Physijs collision events

I have two boxes. One spawns on the ground and the other is dropped on top of it. Gravity is turned on. I am trying to get the collision event listener to fire on the bottom box which is resting on the ground. However, nothing is logged.
var c = new Physijs.BoxMesh( new THREE.CubeGeometry( 5, 5, 5 ), new THREE.MeshBasicMaterial({ color: 0x888888 }) );
c.__dirtyPosition = true;
c.position.set(10, 0,-5);
c.addEventListener('collision', function(object){
console.log("hello world"); // NOT FIRING
});
scene.add(c);
var p = c.clone();
p.__dirtyPosition = true;
p.position.y = 50;
scene.add(p);
I can't figure out what I'm doing wrong - could it be because of __dirtyPosition?
EDIT: I tested it without clone() and creating the second box anew, but it doesn't make a difference.
EDIT 2: It's worth mentioning that the simulation runs fine I just can't get the listener to work.
Relevant GitHub Issue
It looks like the clone method is part of THREEjs, not Physijs. So your code just clones the physical material, not the physical mesh. You're just going to have to create another BoxMesh using the same code you did for c.

How to automatically update a mesh on changing parameters on THREE.js

I'm new to Threejs and to javascript in general. I'm building a mesh based on a json parameters object and it works great.
Now I'm adding some UI components (button, slider, etc) to change the json and rebuild the mesh. I'm writing some monkey-code and I'm sure it can be avoided. Now my stuff works correctly but I'm sure that the problem can be solved more elegantly.
This is my actual workflow:
on slider change use a callback
that callback calls a setter
the setter change the JSON parameters and rebuild the mesh
I'm sure all this can be automated by simply change the JSON and some javascript magic.
Here is the actual pseudocode:
sliderWidth.onChange( function(newValue) {
MyObject3D.setWidth(newValue);
});
and this is a skelton of my MyObject3D:
var MyObject3D = function(parameters) {
this.parameters = parameters;
this.init();
};
MyObject3D.prototype.init = function() {
var geometry = this.initGeometry();
var material = new THREE.MeshPhongMaterial( { color: this.parameters.color, shading: THREE.FlatShading } );
this.mesh = new THREE.Mesh(geometry, material);
}
MyObject3D.prototype.setWidth = function(n) {
this.parameters.width = n;
scene.remove( this.mesh );
this.init();
scene.add( this.mesh );
}
I'm sure that with the javascript high-dinamicity and with all brand new frameworks this piece of code can be easily automated. I've looked mainly at d3.js and at angular.js. In particular d3.js seems to be perfect with the enter-update-exit paradigm (but I didn't find a standard way to conjugate it with Three.js) and angular for sure has to be something in it.
Any kind of advice on structure, pattern, specific use case or examples based on one of the frameworks mentioned THREE.js, d3.js, angular.js) can be enlightening. Actually I'd prefer a solution with angular.js..
There was an excellent talk about using three.js and angular.js which exactly showcases your problem.
https://www.youtube.com/watch?v=mCIZoLaPJxM&t=8m5s
Im using angular directives that watch on a specific attribute and then execute some logic onchange in my projects.
$scope.$watch($attrs.something, function(changedSomething){
doSomeLogicWith(changedSomething);
});

Categories