Orbit controls; Angle clamping - javascript

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>

Related

SVGRenderer with OrbitControls shows two SVG elements on opposite sides

I create two scenes and two renderers, one is for simple 3D mesh sphere and another is for svg circle. SVG scene sits on top of Mesh scene, like an overlay. Sphere and circle are placed on the same position in 3D space. I use OrbitControls to look around. When program loads I see sphere and the circle in the same place, but when I look around I see another svg sphere on the opposite side. Why do I see two svg icons in 3D space and how to get rid of the second one? I know for sure it is one svg node, not two, but somehow orbit controls see it behind like in the mirror.
Here is demo link: http://mystic-peanut.com/mystic_sites/svgdouble/svg_sandbox.html
Here is code snippet:
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = -50;
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xff0000 );
meshScene = new THREE.Scene();
meshScene.background = new THREE.Color( 0x000000 );
// 3d sphere mesh added to mesh scene
var sphereGeometry = new THREE.SphereGeometry( 51, 60, 40 )
var mesh = new THREE.Mesh( sphereGeometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
mesh.name = 'pointer sphere';
mesh.position.set( 0, 0, 1500 );
meshScene.add( mesh );
// svg circle added to svg scene
node = document.createElementNS( 'http://www.w3.org/2000/svg', 'circle' );
node.setAttribute( 'stroke', 'black' );
node.setAttribute( 'fill', 'blue' );
node.setAttribute( 'r', '10' );
node.style.cursor = 'pointer';
var object = new THREE.SVGObject( node );
object.position.x = 0;
object.position.y = 0;
object.position.z = 1500;
scene.add( object );
meshRenderer = new THREE.WebGLRenderer( { antialias: true } );
meshRenderer.setPixelRatio( window.devicePixelRatio );
meshRenderer.setSize(window.innerWidth, window.innerHeight);
meshRenderer.domElement.style.position = 'absolute';
meshRenderer.domElement.style.top = '0px';
threeJSCanvas.appendChild( meshRenderer.domElement );
renderer = new THREE.SVGRenderer( {alpha: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setQuality( 'low' );
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.top = '0px';
renderer.domElement.style.zIndex = 2;
renderer.setClearColor( 0x000000, 0);
threeJSCanvas.appendChild( renderer.domElement );
// controls
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)
controls.minDistance = 10;
controls.maxDistance = 100;
controls.maxPolarAngle = 2*Math.PI / 3;
controls.minPolarAngle = Math.PI / 3;
This issue was fixed within this ticket:
github.com/mrdoob/three.js/issues/15476

Three JS Animation Screen Blank

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;

Three JS Level Horizon Camera

I've dug around everywhere looking for a solution to this. It seems that on OrbitControls and TrackballControlls the camera wont stay horizontal! As you move around with TrackballControlls the scene starts to roll. OrbitControlls dragging from left to right only rolls the scene. I'd like to be able to use the TrackballControls but keep the camera level with the horizon when moving around the center of the scene. Is this possible?
My code:
// SETUP GLOBAL VARIABLES
var camera, controls, scene, renderer;
// PLANET PHYSICAL LOCATIONS
var sun, mercPL, venPL, earthPL, marsPL, jupPL, satPL, urPL, nepPL;
// TIME, AND SCALARS
var now, scalar, planetScalar;
init();
animate();
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
var container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 100000 );
camera.position.z = 200;
controls = new THREE.OrbitControls( camera, renderer.domElement );
//controls.addEventListener( 'change', render ); // add this only if there is no animation loop (requestAnimationFrame)
controls.enableDamping = true;
controls.dampingFactor = 0.8;
controls.enableZoom = true;
// ADD THE SUN PHYSICAL LOCATION
var geometry = new THREE.SphereGeometry(5, 30, 30, 0, Math.PI * 2, 0, Math.PI * 2);
var material = new THREE.MeshBasicMaterial({color: "Yellow"});
sun = new THREE.Mesh(geometry, material);
scene.add(sun);
var segmentCount = 32,
radius = 80,
geometry = new THREE.Geometry(),
material = new THREE.LineBasicMaterial({ color: 0xFFFFFF });
for (var i = 0; i <= segmentCount; i++) {
var theta = (i / segmentCount) * Math.PI * 2;
geometry.vertices.push(
new THREE.Vector3(
Math.cos(theta) * radius,
Math.sin(theta) * radius,
0));
}
scene.add(new THREE.Line(geometry, material));
var segmentCount2 = 32,
radius2 = 120,
geometry2 = new THREE.Geometry(),
material2 = new THREE.LineBasicMaterial({ color: 0xFFFFFF });
for (var i = 0; i <= segmentCount2; i++) {
var theta = (i / segmentCount2) * Math.PI * 2;
geometry2.vertices.push(
new THREE.Vector3(
Math.cos(theta) * radius2,
Math.sin(theta) * radius2,
0));
}
scene.add(new THREE.Line(geometry2, material2));
//
window.addEventListener( 'resize', onWindowResize, false );
//
render();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
render(); // MUST BE HERE FOR ANIMATION
}
function render() {
renderer.render( scene, camera );
}
Thanks!
Perhaps this can help you ( all the options are commented in the orbit library)
Level Horizon:
controls.minPolarAngle = Math.PI / 2;
controls.maxPolarAngle = Math.PI / 2;
Focus of Orbit:
controls.target = (cube.position);
Result: (Note: My mouse controls are inverted (Orbit Right / Pan Left) )
Three.js Lock Orbit Controls
Edit: After reviewing your comments code, I think this is what you want:
Three.js Orbit Controls pt 2.
The gist is that :
a) you need to provide the camera with an up vector:
camera.up.set( 0, 0, 1 );
And
b) Target the sun with the camera:
camera.lookAt(sun.position);
You can still play with the damping, and lock the angles ( there are also vertical constraints if you need them) and speed up down the yaw, but I hope this gets you closer.

Rotating a 3d vector in THREE.js on two axes

Sorry for posting possible duplicate.
I have two 3d vectors:
center ( 0, 0, 0 )
orb ( 0, 0, 100 )
I want to rotate the orb-vector around the center-vector on both X and the Y axes.
What I'm trying to achieve is the make and object always be in view of the camera in the direction it's facing.
I've tried this but with no luck.
var vector = new THREE.Vector3( 0, 0, 100 );
vector.applyAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI * 0.5 );
vector.applyAxisAngle( new THREE.Vector3( 1, 0, 0 ), Math.PI * 0.5 );
orbBall.position.copy(vector);
"What I'm trying to achieve is the make and object always be in view of the camera in the direction it's facing."
If you are simply trying to ensure that orbBall always faces the camera, and both orbBall and the camera are part of the THREE scene then you can just use lookAt like so:
orbBall.lookAt(camera.position);
if you need to align a particular side of orbBall you can use a null dummy Object3D to do it, by adding the dummy node to the scene and orbBall to the dummy, in something like this:
dummy = new THREE.Object3D();
scene.add(camera); // "camera" is defined however
scene.add(dummy);
dummy.add(orbBall); // "orbBall" is created as usual
// ... not to align dummy+orbBall
dummy.lookAt(camera.position);
// ...and you can just rotate orbBall around "inside" dummy, just once,
/// to face however you like
After digging around this issue I realise that it's quite advanced mathematics.
Check out this lecture about quaternions if you're interested:
https://www.youtube.com/watch?v=mHVwd8gYLnI
So I used #bjorke suggestins and used a dummy object, and it works well.
var container, scene, camera, renderer, controls, stats;
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.set(100, 100, 400);
camera.lookAt(scene.position);
scene.add(camera);
renderer = new THREE.WebGLRenderer( {antialias:true} );
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
var light = new THREE.DirectionalLight(0xffffff); //new THREE.PointLight(0xffffff);
light.position.set( 30, 80, -15 );
scene.add(light);
var boxGeo = new THREE.BoxGeometry( 10, 10, 10);
var axes = new THREE.AxisHelper(1000);
scene.add( axes );
var cameraObj = new THREE.Mesh(boxGeo, new THREE.MeshLambertMaterial( {color: 0x888800}));
scene.add(cameraObj);
var orbSpace = new THREE.Object3D();
scene.add(orbSpace);
var orbBall = new THREE.Mesh(boxGeo, new THREE.MeshLambertMaterial( {color: 0x880088}));
orbBall.position.set(0, 0, cameraObj.position.z + 100);
orbSpace.add(orbBall);
animate();
var camX = 0.3;
var camY = 0;
function animate() {
requestAnimationFrame( animate );
camY += 0.02;
if (camY >= 2) camY = 0;
cameraObj.rotation.x = Math.PI * document.querySelector('#volume').value;
cameraObj.rotation.y = Math.PI * camY;
orbSpace.position.copy(cameraObj.position);
orbSpace.rotation.copy(cameraObj.rotation)
renderer.render( scene, camera );
}
Here's a codepen about how it works:
http://codepen.io/arpo/pen/RrpMJJ
You can update the X angle in the uper right corner

JavaScript interactive 3D Object

I am Trying to create an interactive Sphere with JavaScript for an assignment for HCI, the problem is that I am a novice to JavaScript and Three.js.
what I am after is to make it so when the sphere is clicked on that it displays the statistics of a specific subject. I have created the sphere and made it into an object but I am having trouble with the interaction of the sphere. I don't care if a div or a alert opens when the sphere is clicked on but I just need it to work as a dummy version
below is an example in JavaScript and THREE.js:
var sphere = new Object({}); //declared sphere as an object first.
var angularSpeed = 0.2;
var lastTime = 0;
function animate (){
//update
var time = (new Date()).getTime();
var timeDiff = time - lastTime;
var angleChange = angularSpeed * timeDiff * 0.1 * Math.PI / 1000;
sphere.rotation.y -= angleChange;
sphere2.rotation.sphere -=angleChange;
lastTime = time;
// render
renderer.render(scene, camera);
requestAnimationFrame(function(){ //request new frame
animate();
});
}
// renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// camera
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 500;
// scene
var scene = new THREE.Scene();
//material
var material = new THREE.MeshLambertMaterial({
map:THREE.ImageUtils.loadTexture('images/earth2.jpg')});
//sphere geometry
sphere = new THREE.Mesh(new THREE.SphereGeometry( 100, 50, 50 ), material);
sphere.overdraw = true;
sphere.rotation.x = Math.PI * 0.1;
sphere.position.x= 0; // moves position horizontally (abscissa) + = right and - = left
sphere.position.y= 0; // moves position virtually (ordinate) + = right and - = left
sphere.position.z= 0; // moves position z (applicate) + = forwards and - = backwards
scene.add(sphere);
//animate
animate();
var sphere = new Object:({event});
function statistics(){
alert('You clicked on the div!') // displays the statistics before the rendering
};
sphere.onMouseDown=statistics(event);
.onMouseDown is only available for HTML element. You can't use this function for THREE.js objects, but Raycaster is exactly what you want!
jsfiddle
var container, stats;
var camera, scene, projector, raycaster, renderer, selected, sphere;
var mouse = new THREE.Vector2(), INTERSECTED;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
scene = new THREE.Scene();
var light = new THREE.DirectionalLight( 0xffffff, 2 );
light.position.set( 1, 1, 1 ).normalize();
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( -1, -1, -1 ).normalize();
scene.add( light );
sphere = new THREE.Mesh(new THREE.SphereGeometry( 20, 50, 50 ), new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
projector = new THREE.Projector();
raycaster = new THREE.Raycaster();
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
container.appendChild(renderer.domElement);
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
renderer.domElement.addEventListener( 'mousedown', onCanvasMouseDown, false);
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.lookAt(new THREE.Vector3(0,0,0));
camera.position = new THREE.Vector3(0,100,100);
// find intersections
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
selected = raycaster.intersectObjects( scene.children );
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
//detect mouse click on the sphere
function onCanvasMouseDown( event ){
if(selected[0].object==sphere){
statistics();
}
}
function statistics(){
alert('You clicked on the div!') // displays the statistics before the rendering
};

Categories