I currently have a New Jersey d3js map. A 3D map is created out of a topo.json.
I'm trying to find a way to make my map rotate on a fixed axis where I choose to make it appear, but instead, it decides to go over the scene. Scrolling makes it go around a globe instead of just rotating on itself. I've seen a lot of answers in SO and videos about examples that work perfectly out of the box like I'm expecting my model to do, but it just simply decides to scroll around like a globe.
It makes sense to set up a pivot and rotate around it, but I'm stuck figuring out how to make it work.
var pivot = new THREE.Object3D();
pivot.position.set(0,0,0);
pivot.rotation.set(0,0,0);
scene.add(pivot);
This is my current map.
Repository: https://github.com/max-benzait/d3js-new-jersey
Github Page: https://max-benzait.github.io/d3js-new-jersey/
It rotates as if it was going around a globe, and I'm looking to make it scroll like in this example.
var camera, scene, renderer, mesh;
var local = false;
init();
animate();
function init() {
// Camera setup
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.set( 1, 2, - 2 );
// Scene setup
scene = new THREE.Scene();
camera.lookAt( scene.position );
// Cube Setup
var geometry = new THREE.BoxBufferGeometry( 0.5, 0.5, 0.5 );
var material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh( geometry, material );
mesh.position.set(0.5,0.5,0.5);
// Note: Until the mesh is rotated, global and local rotation are the same
mesh.rotation.y = 0.5;
scene.add( mesh );
// Add grid and axes
scene.add( new THREE.GridHelper( 4, 10 ) );
scene.add( new THREE.AxesHelper() );
// Add renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// Create rotation toggle button
var button = document.createElement("button");
button.innerText = "Local Rotation Off";
button.onclick = () => {
local = !local
if (local) button.innerText = "Local Rotation On";
else button.innerText = "Local Rotation Off";
};
document.body.appendChild(button);
}
function animate() {
requestAnimationFrame( animate );
// This is GLOBAL
if (!local) mesh.rotation.x += 0.03;
// This is LOCAL
else mesh.rotateX(0.03);
renderer.render( scene, camera );
}
body {
margin: 0;
}
button {
position: absolute;
top: 10px;
left: 10px;
}
<script src="//cdn.rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
Related
I've been working on a mini project recently for a visuals I want to develop and I'm having issues being able to limit the camera rotation based on the Y axis rotation, and I don't quite know why or how I'm having this issue.
I've looked around and all I can find is people wanting to remove the angle clamp, and they always seem to refer to minAzimuthAngle or maxAzimuthAngle, but I can't seem to get it to do anything.
// controls.minAzimuthAngle = -Math.PI, controls.maxAzimuthAngle = Math.PI
I'm just asking here as I can't find much elsewhere to explain my problem. I'm thinking it's just the specifically the way I'm using or rendering the camera but it's hard to find any reference to clamping the angles other than unclamping them.
var renderer, scene, camera; // scene render var creation
var orbitalControl = new THREE.OrbitControls(camera, renderer); //orbitcontrol setup
var controls = new THREE.OrbitControls( camera, renderer); // camera to renderer
controls.addEventListener( 'change', render ); //control listening
scene = new THREE.Scene(), camera; // scene creation
var W = window.innerWidth, H = window.innerHeight; // scene size
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.set(0, 0, 400); // camera assignment
camera.up = new THREE.Vector3(0,500,0);
controls = new THREE.OrbitControls(camera); // centeralising the camera
controls.target = new THREE.Vector3(500, 200, 500); // controls
controls.addEventListener('change', render); // renderer based on controls
scene.add(camera); // camera to scene
controls.addEventListener( 'change', render ); // control adjustments
controls.screenSpacePanning = false;
controls.enableDamping = true, controls.dampingFactor = 0.25;
controls.enableZoom = false, controls.autoRotate = false;
controls.minPolarAngle = Math.PI / 2 ; // radians
controls.maxPolarAngle = Math.PI / 2 // radians
controls.minAzimuthAngle = -Math.PI * 0.5;
controls.maxAzimuthAngle = Math.PI * 0.5;
controls.addEventListener("change", () => {
if (this.renderer) this.renderer.render(this.scene, camera)});
regardless of whatever I change the min or max AzimuthAngle, it doesn't do anything, but it's the only thing I'm referred to from any other posts.
is there something conflicting with the way I'm trying to render this?
I genuinelly have no clue what the issue is.
Thanks in advance for anyone who responds
github link to the entire project; https://github.com/Thealonic/GENESIS
I'm having issues being able to limit the camera rotation based on the Y axis rotation,
In this case, you have to configure minAzimuthAngle and maxAzimuthAngle. Keep in mind that you can only use values in the range [ - Math.PI, Math.PI ]. Check out how the following example restricts how far you can orbit horizontally.
var mesh, renderer, scene, camera, controls;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 20, 20, 20 );
// controls
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.minAzimuthAngle = 0;
controls.maxAzimuthAngle = Math.PI * 0.5;
// ambient
scene.add( new THREE.AmbientLight( 0x222222 ) );
// light
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 20,20, 0 );
scene.add( light );
// axes
scene.add( new THREE.AxesHelper( 20 ) );
// geometry
var geometry = new THREE.SphereGeometry( 5, 12, 8 );
// material
var material = new THREE.MeshPhongMaterial( {
color: 0x00ffff,
flatShading: true,
transparent: true,
opacity: 0.7,
} );
// mesh
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.115/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.115/examples/js/controls/OrbitControls.js"></script>
I am trying to create an opening door when the user clicks on a sphere in three.js. I tried doing it with a model but I managed to get it to just appear in the correct position rather than rota to it through animation.
I decided to try to focus on an easier scenario and just use a rectangle I would make in three.js. After hours of trying to get it to work I managed to get it to spin and stop when at 90 degrees. However it was rotating around its y axis which was found in the center of the rectangle.
I found this tutorial : https://jsfiddle.net/uxzmsLfr/1/
var camera, scene, renderer;
var mesh, pivot;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.PlaneGeometry( 0.2, 0.5, 0.2 );
var material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh( geometry, material );
mesh.position.set(0, -.25, 0);
scene.add( mesh );
var geo2 = geometry.clone();
geo2.rotateZ(THREE.Math.degToRad(90)); // ROTATE GEOMETRY SO IT'S IN THE CORRECT ORIENTATION
var mesh2 = new THREE.Mesh( geo2, material );
mesh2.position.set( 0, .25, 0 ); // MOVE THE GEOMOETRY UP BY HALF SO PIVOT IS AT THE BOTTOM OF THE GEO
mesh2.rotation.set(0, 0, Math.PI / 2);
mesh.add(mesh2);
pivot = new THREE.Group();
pivot.position.set( 0.0, 0.25, 0 ); // MOVE THE PIVOT BACK TO WORLD ORIGN
mesh.add( pivot ); // THIS ADDS THE PIVOT TO THE CENTRE OF THE GEOMOETRY, WHICH WAS THEN ADDING MESH2 IN THE WRONG PLACE
pivot.add( mesh2 );
// VISUALISE PIVOT
var pivotSphereGeo = new THREE.SphereGeometry( 0.01 );
var pivotSphere = new THREE.Mesh(pivotSphereGeo);
pivotSphere.position.set( 0,0,0 );
pivotSphere.position.z = 0.1;
scene.add( pivotSphere );
scene.add( new THREE.AxesHelper() );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
pivot.rotation.z += 0.01;
renderer.render( scene, camera );
}
And so far I managed to do the same with my code. The only thing that I'm struggling with now is how to remove the stationary rectangle?
I would appreciate any help you can give me.
The example uses the mesh plane to offset the position of the second mesh. You can always use a group for these purposes if you don't want to render anything.
So, replace the line:
mesh = new THREE.Mesh( geometry, material );
with:
mesh = new THREE.Group();
And rename the variable accordingly to not have a confusing code.
There are two plane meshes in the code above. The first one is defined by:
mesh = new THREE.Mesh( geometry, material );
mesh.position.set(0, -.25, 0);
scene.add( mesh );
The second one (the "door") is defined by:
var mesh2 = new THREE.Mesh( geo2, material );
mesh2.position.set( 0, .25, 0 ); // MOVE THE GEOMOETRY UP BY HALF SO PIVOT IS AT THE BOTTOM OF THE GEO
mesh2.rotation.set(0, 0, Math.PI / 2);
mesh.add(mesh2);
Removing the code that defines the first one will remove the non-door rectangle. But you can't simply remove that code can call it a day, because notice the last line of the mesh2 definition:
mesh.add(mesh2);
This means mesh2 was added as a child of mesh. The pivot group is also a child of mesh. In both cases, replace mesh with scene, and you should be good to go.
I am having trouble rotating my 3d man object model horizontally via three.js.
My main confusion is that I dont know if I should to be controlling the camera angle or the object angle in order to achieve this and based on my research, there seemes to be different methods to achieving what I need but I am not sure which method would work with what I implemented so far.
<script src="js/three.js"></script>
<script src="js/OBJLoader.js"></script>
<script src="js/OrbitControls.js"></script>
<script>
var scene, camera, renderer , controls, ambientLight, pointLight, textureLoader, map, material, loader;
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
var SPEED = 0.01;
function init() {
scene = new THREE.Scene();
initChris();
initCamera();
initRenderer();
initControl();
document.body.appendChild(renderer.domElement);
}
function initCamera() {
camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 8000);
ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
pointLight = new THREE.PointLight( 0xffffff, 0.8 );
camera.position.set(0, 0, 4000);
camera.add( pointLight );
scene.add( camera );
scene.add( ambientLight );
camera.lookAt(scene.position);
}
function initRenderer() {
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(WIDTH, HEIGHT);
renderer.setClearColor( 0x000000, 0 );
}
function initControl(){
controls = new THREE.OrbitControls( camera );
controls.enableZoom = false;
controls.minPolarAngle = Math.PI * 0.5;
controls.maxPolarAngle = Math.PI * 0.5;
controls.update();
}
function initChris() {
textureLoader = new THREE.TextureLoader();
map = textureLoader.load('img/CHRIS.BMP');
material = new THREE.MeshPhongMaterial({map: map});
loader = new THREE.OBJLoader();
loader.load( 'obj/CHRIS.OBJ', function ( object ) {
object.traverse( function ( node ) {
if ( node.isMesh ){
node.material = material;
}
});
scene.add( object );
});
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
init();
render();
</script>
I also dont know if there is something wrong with my 3d man model because I tried using different models and each model gave me a different rotation angle. For example, the model I am currently working with is showing my 3d man model at birds-eye-view and the rotation pivot is occuring at his feet while if I change the 3d man model taken from three.js example, I get to see the 3d man model at front view and the rotation pivot is centered which is what I am tryin to achieve with the 3d man model that I am working with.
Any help or advise is greatly appreciated.
I'm new to three js and webgl. I have a complicated solar system I'm building and it all works great until I want to animate anything. Here is a very stripped down version to show the problem (with sun in low res). If I add the line sun.rotate.y += 1; it wont load or run anything at all. I have looked around a lot and can't figure out why. I'm sure it is something stupid I'm missing. Thanks for any help.
<script>
// SETUP SCENE
var camera, controls, scene, renderer;
var container
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 90000 );
camera.position.z = 100;
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = .2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = true;
controls.staticMoving = false;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
controls.addEventListener( 'change', render );
scene = new THREE.Scene();
// ADD THE SUN PHYSICAL LOCATION
var geometry = new THREE.SphereGeometry(5, 3, 3, 0, Math.PI * 2, 0, Math.PI * 2);
var material = new THREE.MeshBasicMaterial({color: "Yellow"});
var sun = new THREE.Mesh(geometry, material);
scene.add(sun);
//RENDER
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
render();
animate();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
render();
}
function animate() {
requestAnimationFrame( animate );
controls.update();
render();
}
function render() {
sun.rotate.y +=1; // Problem animating?
renderer.render( scene, camera );
}
</script>
You need to define sun as a global variable because currently it is not visible in the render() scope.
Also, I think to rotate a mesh you call "rotateX(), rotateY() or rotateZ()" so it is sun.rotateY(0.01)
Edit: I realized you can rotate the mesh by modifying its rotation rather than its rotate property.
You have a scope issue ( well it's complicated depending on what you are using es6 or es5), these are the offending bits:
Declare your global(or not Js will add it) to the global space :
var container, sun;
And refer to it inside the init function:
this.sun = new THREE.Mesh(geometry, material);
Working Pen:
Scope Issue in Three.js
Also, TrackballControls is not part of Three.js, you have to import it, check the pen.
Also, Also,for the rotation you might want to use:
sun.rotation.y += 0.003;
I'm having difficulties wrapping my head around changing the THREEjs rotation. I basically want my camera to rotate around my object and not around the standard point (0,0,0 ?). The reason is that my Vector3 values are fairly large.. (x, z, y)
4312872.381146194 66.59563132658498 -25727937.924670007
4312475.124507734 66.59563132658498 -25728638.83021001
4312004.77886603 133.19126265316996 -25728715.10960813
4311292.30267081 133.19126265316996 -25728348.26316222
4310580.495996718 199.78689397975492 -25727972.97279594
4310080.51032912 199.78689397975492 -25727395.118092548
4309842.889229621 266.3825253063399 -25726583.881802954
4309162.375115815 266.3825253063399 -25726174.132726204
I'm connecting the dots with lines, set the camera position to the bounding box and use OrbitalControls to move around. But the moving the camera isn't focused on my line geometry. How can I change the rotation behaviour? Can anyone put me on the right path?
var renderer,
scene,
camera,
controls
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColorHex( 0xeeeeee, 1.0 );
scene = new THREE.Scene();
var material = new THREE.LineBasicMaterial({
color: 0xff00cc,
fog: true
});
var geometryL = new THREE.Geometry();
Afterwards I push my data to the Geometry...
var line = new THREE.Line(geometryL, material);
geometryL.computeBoundingBox();
var bBox = geometryL.boundingBox;
console.log(bBox);
var x_max = bBox.max.x;
var y_max = bBox.max.y;
var z_max = bBox.max.z;
scene.add( line );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 5000000);
camera.position.set( x_max*1.01, y_max*1.01, z_max*1.01 );
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', animate );
controls.rotateSpeed = 0.01;
controls.zoomSpeed = 0.01;
controls.panSpeed = 0.08;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 2;
animate();
function animate() {
renderer.render( scene, camera );
};
Simply add the position of the object your camera should rotate around to the camera's position.
camera.position.set( x_max*1.01, y_max*1.01, z_max*1.01 ).add(YourObject.position.clone());
Also you could try change the target of the control:
controls.target = YourObject.position.clone();
I hope that I understood you right, because I'm currently unable to run your code.