I have a json model exported from Revit using RvtVa3c. I added the model to the scene using ObjectLoader.
var loader = new THREE.ObjectLoader(manager);
loader.load( 'mesa.js', function ( object ) {
scene.add(object);
}
Then I tried both...
// From Va3cViewer.js
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( targetList );
and...
// From three js example code
// have onMouseMove event and raycaster initialized elsewhere in the code
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
Both didn't find any intersect. I have read one post about calling computeFaceNormals() on geometry before trying to find intersect, but no children have geometry when I debugged the code. Is there no way to find intersect with object3d? Please help. Many thanks in advance.
Source here.
Just Found this post.
Adding the second argument of "true" seemed to do the trick.
var intersects = raycaster.intersectObjects( targetList, true );
Related
I'have been trying to intersect only one material among 3 materials of the loaded model onclick using their ID's, however, the control continues to the entire model. Let me know if it is possible to intersec on basis of material ID's
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
object.scene.traverse(function(child) {
if ( child instanceof THREE.Mesh ) {
if (child.material.name == "heap") {
child.material.color = new THREE.Color( 0x00ff00 );
}
}
})
}
You can update the material of a raycast object by means of accessing the material property on the object of an intersection result.
Something to keep in mind is that, when you do update the properties of a material object, you need to set needsUpdate = true so threejs knows that the material needs updating internally.
Consider the following code that achieves what you're after:
// If only interested in one intersection, you can use .intersectObject()
var intersection = raycaster.intersectObject( scene.children );
// If intersection found, update material in some way
if(intersection) {
// Extract object and material from intersection
var object = intersection.object;
var material = object.material;
/*
Manipulate your material as you need to
material.color = new THREE.Color( 1, 0, 0 );
*/
// Tell threejs that the material was changed and
// needs to be updated internally
material.needsUpdate = true;
}
I'm trying to animate a polygon in A-frame, seen also here Add polygon in A-frame:
// Create new shape out of the points:
var shape = new THREE.Shape( vector2List );
// Create geometry out of the shape
var geometry = new THREE.ShapeGeometry( shape );
// Give it a basic material
var material = new THREE.MeshBasicMaterial( { color: 0xffffff, opacity: 1} );
// Create a mesh using our geometry and material
var mesh = new THREE.Mesh( geometry, material ) ;
// add it to the entity:
this.el.object3D.add( mesh );
The goal now is to change the opacity of the shape in an animation. I don't know how to access the shape/polygon attributes within the animation - maybe something like this:
// animation
let opacityAnimation = document.createElement( 'a-animation' );
following lines are not clear:
opacityAnimation.setAttribute( 'mesh.material', 'opacity' );
opacityAnimation.setAttribute( 'to', '0' );
opacityAnimation.setAttribute( 'dur', '5000' );
this.el.appendChild( opacityAnimation );
edit:
here is a live-example: fiddle
You set mesh.material to opacity. I believe You want to specify the animated attribute. As the animation element should look like this:
<a-animation attribute="material.opacity"
to = "0"
dur = "5000">
</a-animation>
Your js must be setting those accordingly:
// animation
let opacityAnimation = document.createElement( 'a-animation' );
opacityAnimation.setAttribute( 'attribute', 'material.opacity' );
opacityAnimation.setAttribute( 'to', '0' );
opacityAnimation.setAttribute( 'dur', '5000' );
this.el.appendChild( opacityAnimation );
Now, if you want to use the material component with a custom/polygon geometry, You need to create it a bit differently.
Instead of creating a new mesh, consisting of its own geometry, and material, lets make the geometry in three.js, and use the existing material component.
So i simply replaced adding the new mesh with a simple:
var myShape = new THREE.Shape(points);
var geometry = new THREE.ShapeGeometry(myShape);
this.el.getObject3D('mesh').geometry = geometry;
You should wait till the object3D is loaded to do it properly, in my fiddle i just made a simple timeout.
Now we can use the animation component as intended, and change the material.opacity.
Check it live on a box here.
Check it live on a polygon here.
I have a 3D-model that I'm loading through the JSONloader of three.js.
I want to make it possible that I can click on one of the links of the chain. The model is made in Blender and each link of the chain is a seperate node/object.
For example it should be possible when clicking on a blue link, an alert is fired with 'blue', same for green, etc...
Is that even possible in three.js or should I use other solutions?
Thanks!!
It's absolutely possible with Three.js.
There are two parts to your question:
How to pick objects on screen?
How to identify which one is picked?
Part one is easily answered in many other places. Threejs.org includes a very nice example demonstrating that. It can be found here.
The relevant portion of the code is as follows:
var raycaster, mouse = new THREE.Vector2()
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
// Do something!
}
intersects is an array so you can get the first intersect (i.e. the one in 'front') with intersects[ 0 ] or specifically the Object3D node with intersects[ 0 ].object.
What you do with that is up to you. Based on your example, I would, when creating each object, add a custom property to the object such as:
object.msg = "This is a test message!"
This could then be logged when clicking the object:
var raycaster, mouse = new THREE.Vector2()
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
if (intersects[0].object.msg) {
console.log(intersects[0].object.msg)
}
}
An alternative would be to create an object with messages and UUIDs:
var messages = {
"61f2175b-6908-48dc-9131-55ffa11c8581": "Hello world!"
};
var raycaster, mouse = new THREE.Vector2()
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
var uuid = intersects[0].object.uuid;
if (messages[uuid]) {
console.log(messages[uuid])
}
}
Hopefully this gives you some ideas about how to tackle this problem!
For the human demo http://threejs.org/examples/#webgl_morphtargets_human , I wonder how to get a point on the skin of the human. For example when I click some place on the human body, what's the coordinate of that place?
I tried using the raycaster to get that but in vain.The code is like this:
var projector;
init() {
// Others
// ...
projector = new THREE.Projector();
renderer.domElement.addEventListener('mouseup', onMouseUp, false);
}
function onMouseUp(e) {
e.preventDefault();
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
0.5
);
projector.unprojectVector( vector, camera );
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersections = raycaster.intersectObjects( character.root.children );
if (intersections.length > 0) {
debugger;
// ...
}
}
But the intersections is always empty.
Three.js is r67
Thanks in advance.
I'm new to three.js, and i've also tried to draw plots on the human. I manage to do it, but it's not on the "visible" body. In fact, you should first use the intersect method with the recursive arg :
var intersections = raycaster.intersectObjects( scene.children, true );
Thus, you 'll be able to interact with the objects composing the body, but they are not positioned under the "skin". It seems to be that they have been "moved", because you can interact with them if you aim in front of the feet of the body. Unfortunately, I don't know for the moment why, and how to interact with their "visible representation".
Well, finally I find that it's just because the human animation. It works if I comment the animation out.
I loaded the model using OBJLoader, here is the code for loading the obj file:
var loader = new THREE.OBJLoader();
loader.load('obj/teeth/teeth4_5.obj', function(object) {
model = object;
scene.add( model );
objects.push( model );
});
And I'm trying to use raycaster to find the intersection. I implemented my code from the canvas_interactive_cubes example (http://mrdoob.github.io/three.js/examples/canvas_interactive_cubes.html) in three.js. Here is the code to find the intersection:
function onDocumentMouseDown( event ){
event.preventDefault();
var mouseX = (event.clientX / window.innerWidth)*2-1;
var mouseY = -(event.clientY /window.innerHeight)*2+1;
var vector = new THREE.Vector3( mouseX, mouseY, 0.5 );
projector.unprojectVector( vector, camera );
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( scene.children );
console.log( intersects[0].point);
}
Unfortunately I'm not able to get the x,y,z coordinates of the intersection, no matter where I clicked, it always showed "TypeError: intersects[0] is undefined".
I'm getting stuck here for several days. Can someone tell me a way to get the intersection on a loaded obj file? I appreciate your help.
Try adding the recursive flag like so:
var intersects = raycaster.intersectObjects( objects, true );
three.js r.58