Collada model causes A-Frame to crash when panning around - three.js

I've loaded a Collada .dae model into my A-Frame scene and animated the camera movement around it then use the mouse cursor to orient the camera using universal-controls from the aframe-extras component. About 50% of the time it is fine, but the other times it throws a error:
aframe.js:30870 Uncaught TypeError: Cannot read property '0' of undefined
raycast # aframe.js:30870
intersectObject # aframe.js:16216
intersectObject # aframe.js:16224
from the line:
if ( uvs ) {
var uvs_f = uvs[ f ];
uvA.copy( uvs_f[ 0 ] );// <- that's where this error came from
uvB.copy( uvs_f[ 1 ] );
uvC.copy( uvs_f[ 2 ] );
intersection.uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );
}
It looks very similar to the question here: Three.js drag the object (but it unfortunately does not have an answer)

Looks like there's an issue wherever it's intersection. I think we might have to PR to A-Frame's cursor to catch such errors.

Related

Make children of imported Three.js group follow pointer when their canvas gets hovered

In Three.js, I have a group of meshes that is loaded from outside with help of FBX loader. The group has six meshes inside. My task is to make this meshes follow pointer when they get hovered. More precisely, I'd like to have a sort of magnetic effect (just like navbar items in this pen, but with meshes in Three.js).
I think, firstly, I have to detect, where currently pointer is, i.e. get position of cursor in world coordinates system, and then translate meshes towards it. But when I try to get the position of cursor, it seems to be wrong.
Having said that, I have two questions:
How to get proper cursor's position relative to the world coordinates?
How to change position of each of the group's meshes so that they get translated against the cursor?
Here is what have I done so far:
Hi everyone.
In Three.js, I have a group of meshes that is loaded from outside with help of FBX loader. The group has six meshes inside. My task is to make this meshes follow pointer when their canvas get hovered. More precisely, I'd like to have a sort of magnetic effect (just like navbar items in this pen, but with meshes of Three.js).
I think, firstly, I have to detect, where currently pointer on canvas is, i.e. get position of cursor in world coordinates system, and then translate meshes towards it. But when I try to get the position of cursor, it seems to be wrong.
Having said that, I have two questions:
How to get proper cursor's position relative to the world coordinates?
How to change position of each of the group's meshes so that they get translated against the cursor?
Here is what have I done so far. Function that translates meshes isn't written yet. Mousemove callback returns pretty big digits, though:
// Load object and play a third-party animation
loader.load("Object_001.fbx", (object) => {
mixer = new THREE.AnimationMixer(object);
const action = mixer.clipAction(object.animations[0]);
action.play();
object.traverse((child) => {
if (child.isMesh) {
child.material.map = texture;
child.material.needsUpdate = true;
}
});
scene.add(object);
});
// log coordinates of the pointer
const mouse = new THREE.Vector3();
const position = new THREE.Vector3();
function onMouseMove(event) {
mouse.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1,
0.5
);
mouse.unproject(camera);
mouse.sub(camera.position).normalize();
const distance = -camera.position.z / mouse.z;
position.copy(camera.position).add(mouse.multiplyScalar(distance));
console.log(position);
}
wrapperElement.addEventListener("mousemove", onMouseMove);
Thanks in advance.
Made a codepen here:
https://codepen.io/cdeep/pen/YzxPPZQ
The cursor only exists in the canvas dom element which is a rendering of the camera view frustum.
The easiest way to make the object follow a mouse is to get the point of intersection of the mouse with another object in the 3d scene and set the object position to the intersection point. The above codepen showcases that.
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObjects([ground]);
if(intersects.length) {
const { point } = intersects[0];
cube.position.copy(point.setY(0.5));
}
You could also position it at a fixed distance from the mouse but it looks odd in my opinion:
const distance = 10;
raycaster.setFromCamera( mouse, camera );
const { origin, direction } = raycaster.ray;
cube.position.copy(origin.clone().add(direction.multiplyScalar(distance)));
Documentation for raycaster:
https://threejs.org/docs/index.html?q=ray#api/en/core/Raycaster
Raycasting is used for mouse picking (working out what objects in the
3d space the mouse is over) amongst other things.

Rigged mesh doesn't animate (despite the bones moving)

I have a model with a skeleton, all set up.
I've added the animations and Animation Helper to see the model move.
The result is odd - the bones are moving (according to animation helper rendering), but the actual model itself does not.
It's better explained with an gif:
Animation is attached to the mesh using:
animation = new THREE.Animation( mesh, geometry.animation );
Any suggestions on what might be wrong?
The solution was pretty simple actually:
for ( var k in materials ) {
materials[k].skinning = true;
}

Rescale Scene or Mesh after loading with Sceneloader

I'm not sure why I cannot rescale my scene after loading with sceneLoader.
I have a simple box that I created and exported from blender as js file.
I tried rescaling the entire result scene before and after. I even looped over the mesh objects and tried rescaling but the scale.set has no affect.
var callbackFinished = function ( result ) {
result.scene.scale.set(10,10,10)
scene.add(result.scene);
}
loader.load( "box.js", callbackFinished );
Thanks,
Jim
Nevermind, I managed to solve it. When loading my model with SceneLoader, the verticesNeedUpdate property is set to false. So I had to set all the mesh verticesNeedUpdate to true for the scale to work.

ThreeJs and Blender (using colladaLoader): first contact

How can I render an exported scene (with many objects, each with different colors and different properties, such as rotation aroung an axis in the scene) from Blender (with colladaLoader -->.dae) in ThreeJs?
So, the first step is to learn how to create a scene in threeJs and learn some feature with Blender. When you are ready, create your first model and before exporting keep this in mind:
you need to an object with vertices, so if you just create a text with Blender, you have to convert it to a mesh, otherwise threeJs will not render it
be sure to choose the Blender render option and not the Cycles,
otherwise the .dae you export will not be rendered in threeJs
when applying a texture, use just colors and basic materials (basic, phong and lambert) - the others will not work using the colladaLoader
to see if the object will be rendered with color in threeJs with
colladaLoader just look at object in Blender with object mode
(solid) - if it's gray and not colored of the color you choose, it
will be rendered in threeJs the same way
if you apply the 'solidify' modifier to the object and then on threeJs set it to transparent, it will be rendered as wireframed
if you append multiple objects in the scene and 'join' them, the
respective positions and rotations will be respected in threeJs,
otherwise not: for example, if you want to renderize a flower in the
bottle (and thoose objects are different blender files which are
appended/linked in the scene), the flower will not fit in the bottle
in threeJs, but would have a different position and rotation than
the bottle
grouping the objects will not solve this: to see the scene as you see it in Blender you have to 'join' the objects (with the consequences that this entails) or manually change position and rotation on threeJs
the .dae export options don't matter for the rendering of the object in threeJs
and now, the part that regards threeJs:
be sure to import the colladaLoader with:
<script src="jsLib/ColladaLoader.js"></script>
insert this code into your init() function so the loader will load your .dae model:
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load( 'model.dae', function ( collada ) {
// with this you can get the objects of the scene; the [0] is not the first object
// you display in blender in case of many objects (which means you didn't join them)
var obj1 = collada.scene.children[0];
// you can name the object so you can use it even out of the function, if you want
// animate it for example obj1.name = "daeObj1";
// you can set here some material properties as trasparency
obj1.material.needsUpdate = true;
obj1.material.transparent = true;
obj1.material.opacity = 0.5;
obj1.hearth.material.wireframe = false;
// and now some position and rotation for good visualization
obj1.position.set(0, -5, -0.6); //x,z,y
obj1.rotation.set(0, 45, 0);
// and add the obj to the threeJs scene
scene.add(obj1);
});
and some code to the animate() function if you want to update some of your objects, with rotation for example
scene.traverse (function (object) {
if (object.name === 'daeObj1') {
object.rotation.z -= 0.01;
}
});
I hope someone will benefit from this post

How can I get rid of INVALID_VALUE warning when loading a three.js texture?

Using Three.Js r66 and a setup like so:
var texture = THREE.ImageUtils.loadTexture('/data/radar.png');
texture.wrapS = THREE.RepeatWrapping;
var radar = new THREE.Mesh(
sphere,
new THREE.MeshBasicMaterial({
map: texture,
transparent: true,
}));
I'm getting the following warnings on the console:
WebGL: INVALID_VALUE: texImage2D: invalid image dev_three.js:26190
[.WebGLRenderingContext]RENDER WARNING: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'
I'm pretty sure this is because the object is being rendered before the texture has been loaded, thus WebGL is trying to access a null texture in: three.js line 26190.
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
The code as quoted above works - once the texture has been loaded it displays just fine. I'd like to get rid of the warnings though - any ideas? Other materials (e.g. phong) seem to handle asynchronous texture loading better. They show up black until the texture arrives. Noticeably, they do not spam the console with warnings.
This demo (http://jeromeetienne.github.io/tunnelgl/) exhibits the same problem.
Wait for the texture to load
var safeToRender = true;
var texture = THREE.ImageUtils.loadTexture('/data/radar.png',
undefined,
textureHasLoaded);
function textureHasLoaded() {
safeToRender = true;
}
Then don't start rendering until safeToRender is true.
Of course if you're loading more than 1 image you'll need to use a count or something instead of a flag.

Resources