I have a bug where I copy the Quaternion of one object and pass it to a function where it gets applied to another object to keep their rotations in sync. I cannot get the Quaternion to apply to the second object.
Given object 1 is msh and object 2 is msh2, this code will not apply the rotation of msh to msh2
var rot = new THREE.Quaternion().copy(msh.rotation);
msh2.rotation.copy(rot);
You can see this further in this Stack Snippet which contains the problem in the smallest reproducable fashion (but isn't the exact code I'm working with in my real project)
var renderer = new THREE.WebGLRenderer({canvas : $("#can")[0]});
renderer.setSize($("#can").width(), $("#can").height());
var cam = new THREE.PerspectiveCamera(45, $("#can").width() / $("#can").height(), 0.1, 100);
cam.position.set(0,2,6);
cam.quaternion.multiply(new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), -Math.PI/8 ));
var scene = new THREE.Scene();
var geo = new THREE.BoxGeometry(1,1,1);
var mat = new THREE.MeshBasicMaterial({color : 0xff0000});
var msh = new THREE.Mesh(geo,mat);
scene.add(msh);
geo = new THREE.BoxGeometry(1,2,1);
mat = new THREE.MeshBasicMaterial({color : 0xff00ff});
var msh2 = new THREE.Mesh(geo,mat);
msh2.position.set(2,0,0);
scene.add(msh2);
function render() {
requestAnimationFrame( render );
msh.rotateX(0.001);
msh.rotateY(0.002);
//For some reason, this doesn't work??
var rot = new THREE.Quaternion().copy(msh.rotation);
msh2.rotation.copy(rot);
//Yet this does (but it doesn't fit the flow of my
//original project because I don't want to pass
//objects around.
//msh2.rotation.copy(msh.rotation);
renderer.render( scene, cam );
}
render();
<script src="https://cdn.rawgit.com/mrdoob/three.js/dev/build/three.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="can" width="400" height="300"></canvas>
Also see the JSFiddle here
Am I missing something here? I do this with Vector3 all the time so I don't see why I can't do it here...
msh.rotation is an instance of THREE.Euler, but you're trying to copy to/from THREE.Quaternion. msh2.rotation.copy(msh.rotation) should work fine, as would msh2.quaternion.copy(msh.quaternion)
If I understand you correctly you want both objects to rotate at the same speed and angle. You just need to update the render(); function with these two lines:
msh2.rotateX(0.001);
msh2.rotateY(0.002);
Updated JSFiddle
Related
I'm currently working on a project that involves making 3Dobjects in Threejs, based of databases.
I already have the connection etc, but it keeps failing when I try to create a new object.
this.type = 'CustomObject';
let shape = new THREE.Shape();
const maxSize = coords.reduce((prev, current) => (Math.abs(prev.value) > Math.abs(current.value)) ? prev : current); // max Size but Abs
// console.log("Max size before check : "+ maxSize.value);
//Check weither maxSize is positive or negative.
let height = Math.abs(maxSize.value);
shape.moveTo(0, 0);
for (let i = 0; i < coords.length; i++) {
// console.log(coords[i]);
shape.lineTo(coords[i].id, coords[i].value);
}
shape.lineTo(coords[coords.length - 1].id, -height - 3);
shape.lineTo(0, -height - 3);
shape.lineTo(0, 0);
// let geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
let extrudeSettings = {
steps: 4,
amount: 20,
bevelEnabled: false,
bevelThickness: 1,
bevelSize: 1,
bevelSegments: 1
};
this.geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
this.material = new THREE.MeshBasicMaterial({color: 0xCbcbcb});
let object = new THREE.Mesh( this.geometry, this.material );
this.createdGraph = object;
console.log(this.createdGraph.Object3D);
this.scene.add(this.createdGraph);
}
This is just part of the code, I know it's not the best. But I would like to work it before I clean it.
It's writen with ES6 in mind.
The problem is that if you execute the code, it does create the figure I'd like to have.
A screengrab of the object created by the code.
But if I try to add it to A-Frame ( because I've worked with it before), it keeps giving me the error that I can't add an object without an Object3D to the scene or 'this.updateMorphTargets is not a function ' .
Anyone have any ideas ?
PS I've also tried this https://stackoverflow.com/a/31924233 idea, but that comes back with the ' this.updateMorphTargets is not a function' error.
Thanks :)
I'm not sure which parts give you the error,
I've copied Your code to a fiddle, added 3 coords, and it's working.
Judging from Your code, You've got bad scene references, in a-frame it's
this.el.sceneEl
assuming this is any entity, and this.scene does not refer to the scene.
Furthermore refer to three.js objects as object3D, not Object3D
I've only put the three.js object creation to a aframe component:
AFRAME.registerComponent("foo",{
init:function(){
//Your code here
}
});
and placed an entity:
<a-entity foo> </a-entity>
Also I've placed the object by getting the scene reference, before adding:
this.el.sceneEl.object3D.add(object)
what works:
I am using threejs revision 73.
I want to render a tool with the WebGLRenderer.
The tool consists of 3 Meshes. Each mesh consists of a BufferGeometry and a MeshLambertMaterial:
var geometry = new THREE.BufferGeometry();
var material = new THREE.MeshLambertMaterial();
var mesh = new THREE.Mesh(geometry, material);
The result looks like the following:
what I want to archive:
Now I want to make the tool look more realistic by applying a Texture ("img/tablereflection.bmp", grayscale 256x256px, bmp). I am unsure what is the best approach if I want this texture to affect my reflectivity behavior.
What I do, is:
var geometry = new THREE.BufferGeometry();
var material = new THREE.MeshLambertMaterial({
map: new THREE.TextureLoader().load("img/tablereflection.bmp")
});
var mesh = new THREE.Mesh(geometry, material);
But the result looks like that:
That is not what I want to have. It should look like:
Can someone tell me please, what I might be missing?
Edits
My light function is
function initLight(scene, camera) {
var ambientLight = new THREE.AmbientLight(0x555555);
scene.add(ambientLight);
var leftLight = new THREE.PointLight(0x888888, 0.7, 0);
leftLight.position.set(-2, 5, 2);
camera.add(leftLight);
var rightLight = new THREE.PointLight(0x888888, 0.7, 0);
rightLight.position.set(2, 5, 2);
camera.add(rightLight);
}
I've already tried to use The material browser for MeshLambertMaterial and possibly was able to archieve what I wanted as you can see here using these settings , but as you can see the Type is now empty and so I am not sure what happens behind the scene. Where is the error? Im glad for any hints.
I have a object that I'm adding into my scene. I also have various other cubes in the scene. I'm using the following code to fire a Ray and see if I can detect a collision:
var ray = new THREE.Raycaster(camera.position, vec);
var intersects = ray.intersectObjects( scene.children );
For some reason, the regular shapes (cubes) are detected, but the objects that loaded from the obj files are not.
var loader = new THREE.OBJMTLLoader();
loader.load( 'models/technicalTable1.obj', 'models/technicalTable1.mtl', function ( obj ) {
obj.scale.set(0.4, 0.4, 0.4);
obj.position.x = - roomWidth/2 + 100;
obj.position.y = 36;
obj.position.z = - roomLength/2 + 25;
scene.add( obj );
}, onProgress, onError );
Thanks for any help!
You need to pass the recursive flag to Raycaster.intersectObjects().
var intersects = ray.intersectObjects( scene.children, true );
three.js r.70
It doesnt work because the OBJMTLLoader creates a Three.Group
The Group does not have a raycaster.intersectObjects
(I just finished tracing it down and it went to a non implemented function
This REALLY limits the the use of OBJ objects.
I have tried JSON but since you can not load materials and have to create UVmap I find that I need a person that can 3D model or not be able to use the intersectObjects.
Not sure if this is a bug
In three.js, I want to add a mesh to a position in the scene
I've tried:
// mesh is an instance of THREE.Mesh
// scene is an instance of THREE.Scene
scene.add(mesh)
scene.updateMatrixWorld(true)
mesh.matrixWorld.setPosition(new THREE.Vector3(100, 100, 100))
scene.updateMatrix()
BUT it didn't affect anything.
What should I do ?
I would recommend you to check the documentation over here:
http://threejs.org/docs/#Reference/Objects/Mesh
As you can see on the top of the docu-page, Mesh inherits from "Object3D". That means that you can use all methods or properties that are provided by Object3D. So click on the "Object3D" link on the docu-page and check the properties list. You will find the property ".position". Click on ".position" to see what data-type it is. Paha..its Vector3.
So try to do the following:
// scene is an instance of THREE.Scene
scene.add(mesh);
mesh.position.set(100, 100, 100);
i saw it on a github earlier. (three.js r71 )
mesh.position.set(100, 100, 100);
and can be done for individuals
mesh.position.setX(200);
mesh.position.setZ(200);
reference: https://threejs.org/docs/#api/math/Vector3
detailed explanation is below:
since mesh.position is "Vector3". Vector3() has setX() setY() and setZ() methods. we can use it like this.
mesh.position = new THREE.Vector3() ; //see position is Vector3()
vector1 = new THREE.Vector3();
mesh.position.setX(100); //or this
vector1.setX(100) // because all of them is Vector3()
camera1.position.setZ(100); // or this
light1.position.setY(100) // applicable to any object.position
I prefer to use Vector3 to set position.
let group = new THREE.Group();
// position of box
let vector = new THREE.Vector3(10, 10, 10);
// add wooden Box
let woodenBox = new THREE.Mesh(boxGeometry, woodMaterial);
//update postion
woodenBox.position.copy(vector);
// add to scene
group.add(woodenBox)
this.scene.add(group);
If some one looking for way to update position from Vector3
const V3 = new THREE.Vector3(0,0,0) // Create variable in zero position
const box = new THREE.Mesh(geometry, material) // Create an object
Object.assign(box.position, V3) // Put the object in zero position
OR
const V3 = new THREE.Vector3(0,0,0) // Create variable in zero position
const box = new THREE.Mesh(geometry, material) // Create an object
box.position.copy(V3)
I have some objects added to an Object3D (for grouping elements) and I'm trying to detect clicks on it.
My scene has a size of 600x400, my camera is within a three-object and my event handler code looks like below:
function onDocumentMouseDown( event ) {
event.preventDefault();
var mouse = {};
mouse.x = ( event.clientX / 600 ) * 2 - 1;
mouse.y = - ( event.clientY / 400 ) * 2 + 1;
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, three.camera );
var ray = new THREE.Ray( three.camera.position, vector.subSelf( three.camera.position ).normalize() );
var intersects = ray.intersectObjects( group.children );
alert(intersects.length);
[...]
}
Actually I'm alerting the count of intersected objects. But it stays zero. It couldn't find any intersected objects. I've already played a bit aroud with the x, y and z values of my projection vector - without success.
I've added a stripped down sample for demonstrating this issue on jsfiddle. Maybe someone has a short hint for me what goes wrong with it?
In your fiddle, because you are calling THREE.SceneUtils.createMultiMaterialObject( ), which creates a hierarchical structure, you need to add the recursive flag to ray.intersectObjects().
var intersects = ray.intersectObjects( group.children, true );
EDiT: ray is now an instance of THREE.Raycaster -- not THREE.Ray.
three.js r.58
I had the same problem and WestLangley's answer provides the answer. Great job! For anybody struggling with mouse selection of objects grouped in Object3D wrapper too, I am posting my own solution.
First, I created an array of objects that are selectable - I hope this also saves some performance, as RayCaster doesnt need to search all objects in the scene, but only those you wish to respond to selection. I also attached this array to scene object directly (solely for the fact that it is already accessible from most parts of my app)
scene.selectable = [];
Next step is to push all objects that you wish to make selectable into this array. You will insert only meshes/sprites/etc from your group, not the whole group. Only last line is important here:
var myWrapper = new THREE.Object3D();
var myObject = new THREE.Mesh( something );
myWrapper.add( myObject );
scene.add ( myWrapper );
scene.selectable.push( myObject );
And lastly in your mouse selection routine you will call raycaster like this:
var intersects = ray.intersectObjects( scene.selectable );