I have a light that is a child to a pivot object:
var pivotpoint = new THREE.Object3D();
pivotpoint.name="pivot";
scene.add(pivotpoint);
var light = new THREE.PointLight( 0xffffff, 1, 100 );
light.name = "light";
light.castShadow = true;
pivotpoint.add( light );
light.position.set(10,25,0);
Now, in my update() method I rotate the pivot object:
var o = scene.getObjectByName("pivot");
if(GLOBAL_KEYS['a'])
{
o.rotation.y += 0.05;
}
if(GLOBAL_KEYS['d'])
{
o.rotation.y -= 0.05;
}
This works perfectly well. I can see my light rotating around the pivot point, casting shadows and all.
However, if I do...
console.log(light.position);
...the position attribute always stays at (10,25,0).
What in god's name do I need to do in order to get the actual light position??
Thanks in advance!
object.position is a local position, relative to the object's parent in the scene graph. To compute position in global space, use getWorldPosition:
const worldPos = new THREE.Vector3();
light.getWorldPosition(worldPos);
console.log(worldPos);
Related
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'm trying to use the three.js lookAt() method on a meshes (from CylinderBufferGeometry) so that it is oriented toward a point, but when I use the .lookAt() method, it causes the mesh to disappear from view.
The cylinder shows up fine if I comment out the .lookAt() method. I'm using a THREE.PerspectiveCamera and the THREE.WebGLRenderer incase that could have anything to do with the issue.
// Build cylinder
var cylinderRadius = 0.15
var cylinderHeight = 20
var geometry = new THREE.CylinderBufferGeometry(cylinderRadius, cylinderRadius, cylinderHeight);
var material = new THREE.MeshBasicMaterial({color: 0xffffff});
var cylinder = new THREE.Mesh(geometry, material);
// Point the cylinder up
cylinder.geometry.rotateX( Math.PI / 2);
cylinder.geometry.translate(0,0, cylinderHeight/2 );
// Move cylinder to position
cylinder.position.x = 10;
cylinder.position.y = 10;
// Look at point
cylinder.lookAt(0,0,15); // <-- ISSUE OCCURS HERE
scene.add(cylinder);
render();
Use cylinder.lookAt(new THREE.Vector3(0,0,15)); instead of cylinder.lookAt(0,0,15);
I need to run raycast off mouse coordinates and check for intersections on a group of Three CSS3DObject objects.
Here is the function:
RayCastCheck = function(event, objects){
var vector = new THREE.Vector3((event.clientX / window.innerWidth)*2 - 1, -(event.clientX / window.innerHeight )*2 + 1, 0.5);
new THREE.Projector().unprojectVector( vector, camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(objects);
console.log(intersects.length);
};
The objects argument is an array of css3dobjects. I am able to use similar function to target drops on the scene to the correct mouse location so I believe my calculation of the mouse point in world space is correct. This led to believe that the Raycaster is does not check intersections on css3dobjects.
My css3dobjects are typically constructed with a div as its element.
createObject = function(){
var element = document.createElement("div");
var obj = new THREE.CSS3DObject(element);
scene.add(obj);
}
My scene is created via this function
//global
var scene;
var camera;
var renderer;
createScene = function(){
camera = new THREE.PerspectiveCamera( 75, 400 / 600, 1, 1000 );
camera.position.z = 500;
scene = new THREE.Scene();
renderer = new THREE.CSS3DRenderer();
renderer.setSize(400, 600);
$(#body).appendChild(renderer.domElement);
}
Do I have all the required elements in the scene to enable raycasting?
Is it possible to perform raycasting on css3dobjects with the css3drenderer?
Thank you for your help
You can just use the usual events with the dom elements. You can even get the relative coordinates:
var x = e.offsetX==undefined?e.layerX:e.offsetX;
var y = e.offsetY==undefined?e.layerY:e.offsetY;
Using Raycaster on css3dobjects won't work. At least this is what I figured out.
Take a look at three.js r76 line 8933. There is the definition of the "raycast" function of the css3dobject.
It is empty so it isn't implemented and won't work because of this of course. probably on a further version. would need this function too
Still isn't implemented in r78.
Using three js is there anyway to define a clipping region for an object? I have for example a parent which contains child objects, I would like to clip the child objects based on the viewport.
Something like...
// Create container and children
var container = new THREE.Object3D();
for(var i = 0; i < 100; i++) {
var geometry = new THREE.PlaneGeometry(i, 0, 0);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var child = new THREE.Mesh(geometry, material);
container.add(child);
}
// Create bounding box which is my viewport
var geom = new THREE.Geometry();
geom.vertices.push(new THREE.Vector3(0, 0, 0));
geom.vertices.push(new THREE.Vector3(10, 0, 0));
geom.vertices.push(new THREE.Vector3(10, 1, 0));
geom.vertices.push(new THREE.Vector3(0, 1, 0));
geom.computeBoundingBox();
// Magic property (THIS DOESNT EXIST)
container.clipRegion = geom.boundingBox;
The final part doesn't exist but is there any way to achieve this with three js? I potentially want to animate the children within the parent and only show the visible region defined by the bounding box.
Update, Added the following image to describe my problem.
The resulting red area is the region I want to make visible, whilst masking anything that lies outside of this region. All other content should be visible.
I have been able to clip an object with another.
See the result here
fiddle
In this fiddle you will see a cube being clip by an sphere. Since this is a demo, there are some things that are not the final code.
You have in the right hand of the screen another camera view, where you see the scene from a high, static point view.
Also, the part of the cube that should be clipped, instead of this is showed green. In the fragment shader, you have to uncomment the discard statement to achieve real clipping.
if (shadowColor.r < 0.9) {
gl_FragColor = vec4 (0.3, 0.9, 0.0, 1.0);
} else {
gl_FragColor = vec4 (0.8, 0.8, 0.8, 1.0);
// discard;
}
It works by creating a spot light that can cast shadows
clippingLight = new THREE.SpotLight ( 0xafafaf, 0.97 );
clippingLight.position.set (100, 200, 1400);
clippingLight.castShadow = true;
scene.add (clippingLight);
The object that has to do the clipping casts shadows, and the object to be clipped receives shadows.
Then, in the animate , we set this light to the camera location
function animate() {
cameraControls.update();
clippingLight.position.x = camera.position.x;
clippingLight.position.y = camera.position.y;
clippingLight.position.z = camera.position.z;
requestAnimationFrame(animate);
}
Now, the parts that have to be visible in the clipped object are the ones at the shadow. We need a shader that handles that. The frag shader code is take from the standard one in the three.js library, just slightly modified.
I am very new working with three.js, so probably there are a lot of thing in the code that can be done better. Just take the idea :-)
I loaded some objects via OBJLoader , loaded object contain one parent and multiple childs; then I apply Raycaster and find clicked child.
Then I want to update position of child object, but initial position comes zero for all childs.
var intersect = intersects[0].object;
intersect.position.y = intersect.position.y + 5; // 0 + 5
But in my scene all looks fine. Also, If i remove clicked object, actually it is removed from scene. I think I missed some point their positions cant be (0,0,0). How can I reach their relative position ?
Here is code for set Transform Control into center of object:
let objLoader = new THREE.OBJLoader();
let mtlLoader = new THREE.MTLLoader();
mtlLoader.load("path/to/mtlFile.mtl", (materials) => {
materials.preload();
objLoader.setMaterials(materials).load("path/to/objFile.obj", (object3d) => {
object3d.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.geometry.computeBoundingBox();
let matrix = new THREE.Vector3();
let offset = child.geometry.boundingBox.getCenter(matrix);
child.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-offset.x, -offset.y, -offset.z));
child.position.copy(offset);
objects.push(child);
}
});
scene.add(object3d);
});
});
Try this, then read position(). I had the same issue, got an answer here. (geom is your Meshes geometry.)
objMesh.centroid = new THREE.Vector3();
for (var i = 0, l = geom.vertices.length; i < l; i++) {
objMesh.centroid.add(geom.vertices[i].clone());
}
objMesh.centroid.divideScalar(geom.vertices.length);
var offset = objMesh.centroid.clone();
objMesh.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-offset.x, -offset.y, -offset.z));
objMesh.position.copy(objMesh.centroid);
The position is relative to the parent
Multiply the position by the transform of the parent to get the world-space coordinates, if that's what you're seeking
That is because all objects in a obj file have their pivot at World 0,0,0
no matter where their local pivot was before exporting.