I'm creating a parent/child hierarchy between three objects using the ".add()" method in Three.js, (RE: 71). Parenting a two objects poses no problems. However, When I attempt to create a three level hierarchy, the middle child jumps to an offset equivalent to the offset of it's parent from the origin.
This is the hierarchy:
Red Box (parent of Green Box) -> Green Box (parent of Blue Box) -> Blue Box
Below is an image of how the boxes should be positioned before and after the parenting:
This is an Image if how the boxes have been repositioned when parented:
The relevant code looks like this:
var testObject_G1 = new THREE.BoxGeometry(50, 100, 100);
var testObject_G2 = new THREE.BoxGeometry(100, 100, 50);
var testObject_G3 = new THREE.BoxGeometry(50, 100, 100);
var testObject_MR = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var testObject_MG = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var testObject_MB = new THREE.MeshBasicMaterial({ color: 0x0000ff });
var testObject_Mesh = new THREE.Mesh(testObject_G1, testObject_MR);
testObject_Mesh.position.x = -100;
var testObject_Mesh2 = new THREE.Mesh(testObject_G2, testObject_MG);
testObject_Mesh2.position.x = 0;
var testObject_Mesh3 = new THREE.Mesh(testObject_G3, testObject_MB);
testObject_Mesh3.position.x = 100;
testObject_Mesh2.add( testObject_Mesh3 );
testObject_Mesh.add( testObject_Mesh2 );
scene.add( testObject_Mesh );
There is a JS Fiddle here: jumping second child
Thank you in advance.
what you see is correct. In a hierarchy the child will inherit the parents transform (inherit is simplification; their matrices will be multiplied but you only have translation defined so the values will be added). So testMesh (red) will appear at x=-100, testMesh2 (green) will also appear at x=-100 (since its x transform is 0 and will inherit its parent transform) and testMesh3 (blue) will appear at x=0 (since -100+0+100=0).
Add this to your fiddle to see the relative transformations.
scene.add( new THREE.AxisHelper( 100 ));
Related
My aim here is to create a box, then change one of its vertex's position through geometry, and then display it.
var anchor = new THREE.Vector3( 300, 300, 3 );
var cursor = new THREE.Vector3( 500, 550, 50 );
var box2 = new THREE.Box3( anchor, cursor );
var box2Helper = new THREE.Box3Helper( box2 );
box2Helper.geometry.vetices[0] = new THREE.Vector3( 20, 20, 20 );
box2Helper.geometry.verticesNeedUpdate = true;
scene.add( box2Helper );
This code works fine without those two geometry lines.
What is the way to change the position of the existing vertexes of the box through geometry class?
I think there may be some confusion here about what the Box3 class is... It's just a 3d boundingbox.. To make a deformable box with vertices, you want a new THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshStandardMaterial() )
then you can modify the mesh.geometry.vertices like you are doing..
THREE.Box3 is more of a utility class used to represent bounding boxes of things.. it's used for frustum culling and stuff.
I imported a model and found that shadow only show in a small area(green area in the picture). What can I do to let all objects show their shadow.
Here is my code.
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
light.castShadow = true;
light.shadow.camera.near = 0.01; // same as the camera
light.shadow.camera.far = 1000; // same as the camera
light.shadow.camera.fov = 50; // same as the camera
light.shadow.mapSize.width = 2048;
light.shadow.mapSize.height = 2048;
scene.add( light );
Thanks!!
EDIT:
I add gui to change light.shadow.camera.top / light.shadow.camera.bottom / light.shadow.camera.left / light.shadow.camera.right, but nothing happens.
var gui = new dat.GUI();
gui.add( light.shadow.camera, 'top' ).min( 1 ).max( 100000 ).onChange( function ( value ) {
light.shadow.camera.bottom = -value;
light.shadow.camera.left = value;
light.shadow.camera.right = -value;
});
That's happening because directional lights use an OrthographicCamera to draw a shadowmap to cast shadows. If there are objects outside the view of this camera, it won't be able to calculate their shadows, and will have the effect you're seeing outside the green box. If you want to extend the area that this camera covers, you can modify the .left .right .top .bottom properties of this shadow camera to cover your entire scene. I'm using a box of 100 units in the example below;
var side = 100;
light.shadow.camera.top = side;
light.shadow.camera.bottom = -side;
light.shadow.camera.left = side;
light.shadow.camera.right = -side;
... but you can change the dimensions to whatever you need. Keep in mind that .fov does nothing in your example code because ortho cameras don't use the field-of-view property.
All right, it would be great if you could show me a live example of your code as I have fixed this before for a project in boxelizer.com
The issue can be fixed by changing the light.shadow.camera.left, right, bottom and top properties as suggested before, however we might not be able to see what the effective area of our shadow might be and hence we might be really close to fixing it but not at all. My suggestion is using a helper momentarily just to see the effective shadow area of your light with:
var shadowHelper = new THREE.CameraHelper( light.shadow.camera );
scene.add( shadowHelper );
You are also welcome to see all the code I used in the link I referenced to.
Here's a function I use to set the shadowMap dimensions and coverage area:
//sz is the size in world units that the shadow should cover. (area)
// mapSize is the width,height of the texture to be used for shadowmap (resolution)
var setShadowSize=(light1, sz, mapSz)=>{
light1.shadow.camera.left = sz;
light1.shadow.camera.bottom = sz;
light1.shadow.camera.right = -sz;
light1.shadow.camera.top = -sz;
if(mapSz){
light1.shadow.mapSize.set(mapSz,mapSz)
}
}
setShadowSize(myLight,15.0,1024);
I would like to know if we can have an equirectangular panorama on the foreground and a mesh in the background so when users move across the panorama, the mouse would be able to pickup the plane information from behind.
I have tried loading a panorama using the below code but I couldn't find any way to layer a mesh in the background.
var sphereBufferGeometry = new THREE.SphereGeometry(500,60,40);
sphereBufferGeometry.scale( -1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {
map: new THREE.TextureLoader().load( [panorama image])});
var mesh = new THREE.Mesh( sphereBufferGeometry, material );
scene.add( mesh );
I have also tried loading the mesh(.obj) using the below code but the variable 'object' is of type THREE.Group and the variable 'child' returns multiple objects of type THREE.MESH. So, I am not sure how we can layer a panorama in the foreground.
objLoader.load( [objfile], function ( object ) {
object.traverse( function ( child ) {
});
});
Any help would be appreciated.
Thanks
Put the image on the page and add an image map to it. Do whatever you want with any cell that fires an event. For proof-of-concept, I simply logged the coordinates - top-left-corner ordered pair and bottom-right-corner ordered pair - for cells firing click events.
You could replace click with mouseover/-out calls. If you reduce the cell heights and width to 1px, you could track exact position as the mouse crosses the image...WARNING - lots of event-handling there.
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript"">
// convenience reference
function get(eId) {return document.getElementById(eId);};
// add area elements to an existing image map
function paintMapGrid(imageId, gridId, cellHeight, cellWidth) {
var imgHeight = get(imageId).height;
var imgWidth = get(imageId).width;
var lastJ = Math.floor(imgWidth/cellWidth);
var lastI = Math.floor(imgHeight/cellHeight);
var grid = '';
for (var i = 0; i < lastI; i++) {
for (var j = 0; j < lastJ; j++) {
var coords= (cellWidth*j) + ',' + (cellHeight*i) + ',' +(cellWidth*(j+1) + ',' + (cellHeight*(i + 1)));
grid += '<area onclick="logCellCoords(this);" shape="rect" coords="' + coords + '">';
}
}
get('mesh').innerHTML = grid;
};
function logCellCoords(cRef) {
console.log(cRef.coords);
};
window.onload = function() {
// paint an image map on the image with id='meshImage', adding the
// area elements to the map with id="mesh"; cells are 16px wide
// and 16px tall
paintMapGrid('meshImage', 'mesh', 16, 16);
};
</script>
</head>
<body>
<div>
<img src="yourPanoramicImage.jpg" alt="some 1024x668 panorama"
width="1024" height="668" usemap="#grid" id="meshImage"
/>
<map name="grid" id="mesh"></map>
</div>
</body>
</html>
Afterthoughts...prob'ly less resource intensive to create each area element individually in the inner for loop and append it to its map parent rather than creating the entire HTML string for all and adding it all at once. Also, not sure how tolerant browsers would be for 1px areas, e.g., 1024x668 would need 684,032 area tags. My POC required 64x41 = 2624 area tags.
I was able to find a solution. The idea is to have both spheregeometry and mesh in the same scene and make any initial position/rotation/scale changes to the mesh so that it aligns with the panorama. Once this is the done, any changes to the camera would affect both the objects in exactly same way giving the user an impression that these two objects are always aligned.
I am trying to change color of a selected vertex dynamically. Referring to https://jsfiddle.net/pmankar/m70cpxes/, I created a IcosahedronGeometry point cloud geometry and on click event I would like to change the color of vertex 100.
document.addEventListener('click', function() {
mesh.geometry.colorsNeedUpdate = true;
mesh.geometry.colors[100] = new THREE.Color("rgb(255,0,0)");
console.log(mesh.geometry);
})
Now, I have two questions:
How to make the vertex 100 change its colors
Why is it showing random color to the point cloud
You declared var material, then created materail = new THREE.PointsMaterial(); and then applied material again to your mesh. There's a typo: material != materail.
Also, to have different colors of vertices you have to set colors of them
geometry = new THREE.IcosahedronGeometry(102, detailsLevel);
var colors = [];
geometry.vertices.forEach(function(){
colors.push(new THREE.Color(0xffffff));
});
geometry.colors = colors;
and then in your material you have to set vertexColors as THREE.VertexColors
material = new THREE.PointsMaterial( { size:4, vertexColors: THREE.VertexColors} );
after all, in your "click" event listener you can do
mesh.geometry.colors[100].set(0xff0000);
mesh.geometry.colorsNeedUpdate = true;
jsfiddle example
I added a WireframeHelper to my scene like this:
var wfh = new THREE.WireframeHelper(mesh, 0x000000);
wfh.material.linewidth = 2;
scene.add(wfh);
How do I change the wireframeHelpers position?
I tried:
wfh.position.x += 10;
and
wfh.matrixAutoUpdate = true
wfh.applyMatrix(new THREE.Matrix4().makeTranslation(10, 0, 0));
The second one moves my wireframeHelper but not to the position it should move.
The WireframeHelper will move, automatically, when the mesh is moved. Move the mesh, instead.
If you want to see only the helper, you can set mesh.visible = false, but the mesh must be included in the scene graph.
three.js r.65