I want to select objects with raycasting, but everytime i want to select something on the three.js gui, the Mousdownevent get triggered.
How can i say something like "if the Gui is in front of the object, dont trigger"
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
function onDocumentMouseDown( event ) {
if (event){}
the gui is a normal three.js gui made like this:
gui = new GUI( { width: 330 } );
One way to solve this is with jQuery and an additional control variable:
$( gui.domElement ).mouseenter(function(evt) {
enableRaycasting = false;
} );
$( gui.domElement ).mouseleave(function() {
enableRaycasting = true;
} );
You can then use enableRaycasting in order to determine if raycasting should happen.
Demo: https://jsfiddle.net/gnwz5ae7/
Related
Has anyone had any luck implementing bloom effects or other post-processing effects from https://threejs.org/docs/#examples/en/postprocessing/EffectComposer into a scene?
I’ve come across this a few times and tried to use it but can’t seem to make it work with the latest version of Aframe https://github.com/wizgrav/aframe-effects
I know it's not possible in VR yet and depends on Three work, but is there a way to use them if I'm not intending on my scene being used in VR or AR mode?
If you don't need VR or AR mode, you can use the effect composer "directly" (check out Don McCurdys gist):
Create a THREE.EffectComposer object,
add passes, and
call the composers render on each renderloop .
The "hacky" part is in 3, because you need to override a-frames default behavior.
// assuming this is a component
init: function() {
const renderer = this.sceneEl.renderer;
this.composer = new THREE.EffectComposer(renderer);
// add some passes ..
// (...)
// override `render`
this.bind();
},
// we need to keep the timestamps for the composer.render() function
tick: function (t, dt) {
this.t = t;
this.dt = dt;
},
// Bind the EffectComposer to the A-Frame render loop.
bind: function () {
const renderer = this.sceneEl.renderer;
const render = renderer.render;
const system = this;
let isDigest = false;
renderer.render = function () {
if (isDigest) {
render.apply(this, arguments);
} else {
isDigest = true;
system.composer.render(system.dt);
isDigest = false;
}
};
Check it out in this glitch;
As mentioned, all credit to Don and his gist.
Keep in mind - a-frame does not have most stuff from the threejs examples, so you may need to include them separately (like i did with the passes and shaders in my glitch)
Here is a Three.js Example from stemkoski, now I want to use this Texture-Animation plane or box in A-frame page, how can I Combine it.
A-frame Version: 0.9.0
I couldn't find any examples.
When integrating three.js pieces into aframe, it's recommended to use custom components. Here's a simple example:
js
AFRAME.registerComponent('foo', {
// this is called upon initialization
init: function() {
// we'll need this later on for updating the animation
this.animator = null
// wait until the component is loaded
this.el.addEventListener('loaded', e => {
// copied straight from stemkoski's code:
var runnerTexture = new THREE.ImageUtils.loadTexture( 'images/run.png' );
this.animator = new TextureAnimator( runnerTexture, 10, 1, 10, 75 );
// apply the texture to our element
let mesh = this.el.getObject3D('mesh')
mesh.material.map = runnerTexture
mesh.material.needsUpdate = true
})
},
// this is called before each render loop
tick: function(time, delta) {
// update only if animator was created
if (!this.animator) return
this.animator.update(1000 * delta);
}
})
HTML:
<a-plane foo></a-plane>
glitch here. To make it work with a glitch i had to preload the image with a-assets due to cors issues.
I need to have multiple identical, animated models on a scene. If possible, I would like them to have a shared geometry and material, but if it is impossible, having them instanced per model will suffice too.
Unfortunately, the only way to achieve this result I found is to go through JSONLoader for every model instance.
SkinnedMesh does have a clone() method, but it seems not to be fully implemented yet. If used and both original and cloned mesh are present on the scene, only one will appear, and cloned one will be without animation.
I have attempted to use this example with shared skeletons:
https://github.com/mrdoob/three.js/pull/11666
...and indeed it works, but I need to be able to play different animations for every model instance, having them all play the same one is not sufficient, sadly. I hoped I could do similar hax and insert my own skeleton (made out of bones from the JSON file), but it behaves very much like if I just used clone() from SkinnedMesh.
I am using this code:
https://github.com/arturitu/threejs-animation-workflow/blob/master/js/main.js
Basically what I'd like to achieve is
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = character.someMagicalClone();
scene.add(character);
scene.add(character2);
(...)
I need any clue... and while I wait for help, I am busily deconstructing constructor for SkinnedMesh and JSONLoader for clues ;)
Thanks in advance!
I found a solution in this pull request:
https://github.com/mrdoob/three.js/pull/14494
in short, there are two functions added:
function cloneAnimated( source ) {
var cloneLookup = new Map();
var clone = source.clone();
parallelTraverse( source, clone, function ( sourceNode, clonedNode ) {
cloneLookup.set( sourceNode, clonedNode );
} );
source.traverse( function ( sourceMesh ) {
if ( ! sourceMesh.isSkinnedMesh ) return;
var sourceBones = sourceMesh.skeleton.bones;
var clonedMesh = cloneLookup.get( sourceMesh );
clonedMesh.skeleton = sourceMesh.skeleton.clone();
clonedMesh.skeleton.bones = sourceBones.map( function ( sourceBone ) {
if ( ! cloneLookup.has( sourceBone ) ) {
throw new Error( 'THREE.AnimationUtils: Required bones are not descendants of the given object.' );
}
return cloneLookup.get( sourceBone );
} );
clonedMesh.bind( clonedMesh.skeleton, sourceMesh.bindMatrix );
} );
return clone;
}
function parallelTraverse( a, b, callback ) {
callback( a, b );
for ( var i = 0; i < a.children.length; i ++ ) {
parallelTraverse( a.children[ i ], b.children[ i ], callback );
}
}
As I understand it rebinds cloned skeleton to the cloned mesh.
so topic example could look like:
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = cloneAnimated(character); // <-- used that new function
scene.add(character);
scene.add(character2);
(...)
I'm having trouble stopping a tween in three.js, using tween.js.
The docs state to use tween.stop(), but that doesn't seem to work.
Example here:
http://jsfiddle.net/feLzjzy9/1/
As you hover with the mouse over a box, it starts to change color. This animation takes 10 seconds, but I try to stop it just to test the .stop() feature using setTimeout(function(){ tween.stop() }, 1000);but it doesn't do a thing...
Any help is much appreciated!
There is Reference problem and update problem.
I made some changes in you code. It is not a solution, you can use each change individually.
Best solution is to make each tween as var inside a function, integrate counting in tweened objects and use onUpdate(function(){if(this.counter > 1000){tween.stop}}) (INTERSECTED.material.color) because you creating a lot of unrefferenced timers and tweens, which will be a performance problem.
function animate() {
//
TWEEN.update();
//
}
if (intersects.length > 0) {
if (INTERSECTED != intersects[0].object) {
if (INTERSECTED) INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
INTERSECTED = intersects[0].object;
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
//INTERSECTED.material.emissive.setHex(0xff0000);
TWEEN.remove(tween);
tween = new TWEEN.Tween(INTERSECTED.material.color).onStart(function(){
setTimeout(function(){ tween.stop() }, 1000); ///not good
}).start();
.to({r: 0, g: 25, b: 155}, 10000) /// here set correct time
.easing(TWEEN.Easing.Quartic.In)
.start();
setTimeout(function(){ tween.stop() }, 1000);/// will not work if you create anoter it that one second
}
else {
if(tween) tween.update(time); // bad
}
}
First of all, thank you for this wonderfull work, i'm having a lot of fun working with three.js.
I tried to find answer about a recurent issue, .WebGLRenderingContext: GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2
I'm making a website in webgl, i spend few week understanding all about three.js but i can't fix this issue.
I get this message on Chrome and firefox (latest) each time i try to load a canvas into a map, bumpmap and specmap.
All my mesh are loaded from obj files, by the way i rewrote OBJMTLLoader.js to be able to load more parameters from obj files and more.
here the code used to load image.
THREE.MTLLoader.loadTexture = function ( url, mapping, onLoad, onError ) {
var isCompressed = url.toLowerCase().endsWith( ".dds" );
var texture = null;
if ( isCompressed ) {
texture = THREE.ImageUtils.loadCompressedTexture( url, mapping, onLoad, onError );
} else {
var image = new Image();
texture = new THREE.Texture( image, mapping );
var loader = new THREE.ImageLoader();
loader.addEventListener( 'load', function ( event ) {
texture.image = THREE.MTLLoader.ensurePowerOfTwo_( event.content );
texture.needsUpdate = true;
if ( onLoad )
onLoad( texture );
} );
loader.addEventListener( 'error', function ( event ) {
if ( onError ) onError( event.message );
} );
loader.crossOrigin = this.crossOrigin;
loader.load( url, image );
}
return texture;
};
I'm pretty sure it is from this, because when i disable this function, no more warning.
Is it because the mesh has a texture with an empty image while loading datas ?
Is there any restriction on the dimensions of image ?
For now everything works fines, but i feel strange having those message in console.
Thanks
This error become because the Three.js buffers are outdated. When your add some textures (map,bumpMap ...) to a Mesh, you must recompose the buffers like this :
ob is THREE.Mesh, mt is a Material, tex is a texture.
tex.needsUpdate = true;
mt.map = tex;
ob.material = mt;
ob.geometry.buffersNeedUpdate = true;
ob.geometry.uvsNeedUpdate = true;
mt.needsUpdate = true;
That's all folks !
Hope it's help.
Regards.
Sayris