Screen goes blank when moving camera - three.js

I'm attempting to create something in three.js and I'm moderately successful in building the geometry from text files. To start off, I manage to get a game level file to display complete with textures. Then I try to load the models from that game and suddenly the screen would go blank as soon as I try to move around. I can look around, but moving kills the screen.
I then remove the part about loading the models, but still keep their position in memory, and the same thing happens.
After taking a good look, it turns out that after I set the camera's position to the player's position, then try to move, that is when the screen goes blank.
Some of the code snippet involving how the camera is set up:
var getPlayers = document.createElement("select");
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 10000 );
var LOADING_COMPLETE = false;
A whole bunch of loading functions follow...
function CompleteTheLoading()
{
document.getElementById("mainmenu").innerHTML = "<b>Jump to </b>";
document.getElementById("mainmenu").appendChild(getPlayers);
yawObject.position.x = jklthings[getPlayers.value][3];
yawObject.position.y = jklthings[getPlayers.value][4];
yawObject.position.z = jklthings[getPlayers.value][5];
yawObject.rotation.z = jklthings[getPlayers.value][7]*Math.PI/180;
LOADING_COMPLETE = true;
animate();
}
getPlayers.onchange = function()
{
velocity.x = 0;
velocity.y = 0;
velocity.z = 0;
yawObject.position.x = jklthings[getPlayers.value][3];
yawObject.position.y = jklthings[getPlayers.value][4];
yawObject.position.z = jklthings[getPlayers.value][5];
yawObject.rotation.z = jklthings[getPlayers.value][7]*Math.PI/180;
if (document.activeElement != document.body) document.activeElement.blur();
}
var mouseX = 0;
var mouseY = 0;
var mouseK = 0;
var havePointerLock = 'pointerLockElement' in document ||
'mozPointerLockElement' in document ||
'webkitPointerLockElement' in document;
var moveForward = false;
var moveBackward = false;
var moveLeft = false;
var moveRight = false;
var canJump = false;
var prevTime = performance.now();
var velocity = new THREE.Vector3();
var direction = new THREE.Vector3();
var onKeyDown = function ( event ) {
switch ( event.keyCode ) {
case 38: // up
case 87: // w
moveForward = true;
break;
case 37: // left
case 65: // a
moveLeft = true;
break;
case 40: // down
case 83: // s
moveBackward = true;
break;
case 39: // right
case 68: // d
moveRight = true;
break;
}
};
var onKeyUp = function ( event ) {
switch( event.keyCode ) {
case 38: // up
case 87: // w
moveForward = false;
break;
case 37: // left
case 65: // a
moveLeft = false;
break;
case 40: // down
case 83: // s
moveBackward = false;
break;
case 39: // right
case 68: // d
moveRight = false;
break;
case 78: // n
if(getPlayers.selectedIndex==getPlayers.length-1)
getPlayers.selectedIndex=0;
else
getPlayers.selectedIndex=getPlayers.selectedIndex+1;
getPlayers.onchange();
break;
case 80: // p
if(getPlayers.selectedIndex==0)
getPlayers.selectedIndex=getPlayers.length-1;
else
getPlayers.selectedIndex=getPlayers.selectedIndex-1;
getPlayers.onchange();
break;
case 13: // Enter
getPlayers.onchange();
break;
}
};
document.addEventListener( 'keydown', onKeyDown, false );
document.addEventListener( 'keyup', onKeyUp, false );
var pitchObject = new THREE.Object3D();
pitchObject.add( camera );
var yawObject = new THREE.Object3D();
yawObject.add( pitchObject );
scene.add(yawObject);
var PI_2 = Math.PI / 2;
camera.rotation.x = 90*Math.PI/180;
function animate()
{
var time = performance.now();
var delta = ( time - prevTime ) / 1000;
velocity.x -= velocity.x * 1.0 * delta;
velocity.y -= velocity.y * 1.0 * delta;
velocity.z -= velocity.z * 1.0 * delta;
direction.z = Number( moveForward ) - Number( moveBackward );
direction.x = Number( moveLeft ) - Number( moveRight );
direction.normalize(); // this ensures consistent movements in all directions
if ( moveForward || moveBackward )
{
velocity.y -= direction.z * 1.0 * -delta;
velocity.z -= direction.z * pitchObject.rotation.x * 1.0 * -delta;;
}
if ( moveLeft || moveRight )
velocity.x -= direction.x * 1.0 * delta;
if(mouseK==1)
{
yawObject.rotation.z -= mouseX * 0.01;
pitchObject.rotation.x -= mouseY * 0.01;
pitchObject.rotation.x = Math.max( - PI_2, Math.min( PI_2, pitchObject.rotation.x ) );
}
yawObject.translateX( velocity.x * delta );
yawObject.translateY( velocity.y * delta );
yawObject.translateZ( velocity.z * delta );
renderer.render( scene, camera );
prevTime = time;
requestAnimationFrame( animate );
}
function mouseMovement(e)
{
mouseX = e.movementX || e.mozMovementX || e.webkitMovementX || 0;
mouseY = e.movementY || e.mozMovementY || e.webkitMovementY || 0;
}
renderer.domElement.addEventListener( 'mousedown', function()
{
if(LOADING_COMPLETE==true)
{
mouseK = 1;
document.addEventListener("mousemove", mouseMovement, false);
}
},false);
renderer.domElement.addEventListener( 'mouseup', function()
{
// Ask the browser to release the pointer
document.removeEventListener("mousemove", mouseMovement, false);
mouseX = 0;
mouseY = 0;
mouseK = 0;
},false);
Now, you are probably noticing that the camera is set at an angle. This is due to that the game is Z-up while three.js is Y-up. Rotating and recalculating the whole level is no fun, so I just jumble the camera instead.
Also, for the most part when I change getPlayers it still renders, but after I move I can't get it back even after getPlayers.
Making snippet, and oddly enough that works when setting the position of the yawObject. Except it won't run in this snippet. But here it is anyways.
<html>
<head>
<title>test</title>
</head>
<body>
<script src="https://threejs.org/build/three.js"></script>
<script>
var LOADING_COMPLETE=true;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 10000 );
// A whole lot of Loading Functions removed...
// All that remains is three's Materials Example:
var geometry = new THREE.TorusKnotGeometry( 10, 3, 100, 16 );
var mesh = new THREE.Mesh( geometry, new THREE.MeshNormalMaterial({}) );
scene.add( mesh );
var mouseX = 0;
var mouseY = 0;
var mouseK = 0;
var havePointerLock = 'pointerLockElement' in document ||
'mozPointerLockElement' in document ||
'webkitPointerLockElement' in document;
var moveForward = false;
var moveBackward = false;
var moveLeft = false;
var moveRight = false;
var canJump = false;
var prevTime = performance.now();
var velocity = new THREE.Vector3();
var direction = new THREE.Vector3();
var onKeyDown = function ( event ) {
switch ( event.keyCode ) {
case 38: // up
case 87: // w
moveForward = true;
break;
case 37: // left
case 65: // a
moveLeft = true;
break;
case 40: // down
case 83: // s
moveBackward = true;
break;
case 39: // right
case 68: // d
moveRight = true;
break;
}
};
var onKeyUp = function ( event ) {
switch( event.keyCode ) {
case 38: // up
case 87: // w
moveForward = false;
break;
case 37: // left
case 65: // a
moveLeft = false;
break;
case 40: // down
case 83: // s
moveBackward = false;
break;
case 39: // right
case 68: // d
moveRight = false;
break;
case 78: // n
if(getPlayers.selectedIndex==getPlayers.length-1)
getPlayers.selectedIndex=0;
else
getPlayers.selectedIndex=getPlayers.selectedIndex+1;
getPlayers.onchange();
break;
case 80: // p
if(getPlayers.selectedIndex==0)
getPlayers.selectedIndex=getPlayers.length-1;
else
getPlayers.selectedIndex=getPlayers.selectedIndex-1;
getPlayers.onchange();
break;
case 13: // Enter
getPlayers.onchange();
break;
}
};
document.addEventListener( 'keydown', onKeyDown, false );
document.addEventListener( 'keyup', onKeyUp, false );
var pitchObject = new THREE.Object3D();
pitchObject.add( camera );
var yawObject = new THREE.Object3D();
yawObject.add( pitchObject );
scene.add(yawObject);
var PI_2 = Math.PI / 2;
camera.rotation.x = 90*Math.PI/180;
yawObject.position.x = 10.7;
yawObject.position.y = 20.2;
yawObject.position.z = 0;
yawObject.rotation.z = 135*Math.PI/180;
animate();
function animate()
{
var time = performance.now();
var delta = ( time - prevTime ) / 1000;
velocity.x -= velocity.x * 1.0 * delta;
velocity.y -= velocity.y * 1.0 * delta;
velocity.z -= velocity.z * 1.0 * delta;
direction.z = Number( moveForward ) - Number( moveBackward );
direction.x = Number( moveLeft ) - Number( moveRight );
direction.normalize(); // this ensures consistent movements in all directions
if ( moveForward || moveBackward )
{
velocity.y -= direction.z * 1.0 * -delta;
velocity.z -= direction.z * pitchObject.rotation.x * 1.0 * -delta;;
}
if ( moveLeft || moveRight )
velocity.x -= direction.x * 1.0 * delta;
if(mouseK==1)
{
yawObject.rotation.z -= mouseX * 0.01;
pitchObject.rotation.x -= mouseY * 0.01;
pitchObject.rotation.x = Math.max( - PI_2, Math.min( PI_2, pitchObject.rotation.x ) );
}
yawObject.translateX( velocity.x * delta );
yawObject.translateY( velocity.y * delta );
yawObject.translateZ( velocity.z * delta );
renderer.render( scene, camera );
prevTime = time;
requestAnimationFrame( animate );
}
function mouseMovement(e)
{
mouseX = e.movementX || e.mozMovementX || e.webkitMovementX || 0;
mouseY = e.movementY || e.mozMovementY || e.webkitMovementY || 0;
}
renderer.domElement.addEventListener( 'mousedown', function()
{
if(LOADING_COMPLETE==true)
{
mouseK = 1;
document.addEventListener("mousemove", mouseMovement, false);
}
},false);
renderer.domElement.addEventListener( 'mouseup', function()
{
document.removeEventListener("mousemove", mouseMovement, false);
mouseX = 0;
mouseY = 0;
mouseK = 0;
},false);
window.onresize = function()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
</script>
</body>
</html>
EDIT:
Following Jim's advice, I've reconstructed the code bit by bit, keeping the "teleportation" part, and calling it to some arbitrary numbers. Everything seems to work fine, even after the final touches of loading jklthings. As soon as I change the arbitrary numbers to the coordinates of the jklthings that represent a player, it breaks like above.
Using a console.log(jklthings[getPlayers.value][3] + "\t" + jklthings[getPlayers.value][4] + "\t" + jklthings[getPlayers.value][5] + "\t" + jklthings[getPlayers.value][7]*Math.PI/180); I get the values -4.9 5.9 .1 0. Feeding these in manually, everything works.

Related

How to create rotation on perspective camera on Three.js?

I have build a little 3D-TileMap in Three.js.
Currently, i have problems with my PerspectiveCamera. I wan't to add some camera handling like Map rotating or zooming. The zooming always works, here i'm only use the field of view and mousewheel.
But how i can implement a rotating of my map? When i'm using the coordinates of camera to modify x, y or z, i've misunderstand the calculation.
Here is my current work:
function Input(renderer, camera) {
var press = false
var sensitivity = 0.2
renderer.domElement.addEventListener('mousemove', event => {
if(!press){ return }
camera.position.x += event.movementX * sensitivity
camera.position.y += event.movementY * sensitivity
camera.position.z += event.movementY * sensitivity / 10
})
renderer.domElement.addEventListener('mousedown', () => { press = true })
renderer.domElement.addEventListener('mouseup', () => { press = false })
renderer.domElement.addEventListener('mouseleave', () => { press = false })
renderer.domElement.addEventListener('mousewheel', event => {
// Add MIN/MAX LIMITS
const ratio = camera.position.y / camera.position.z
camera.position.y -= (event.wheelDelta * sensitivity * ratio)
camera.position.z -= (event.wheelDelta * sensitivity)
camera.updateProjectionMatrix()
})
}
var controls;
const Type = 'WebGL'; // WebGL or Canvas
var _width, _height, CUBE_SIZE, GRID, TOTAL_CUBES, WALL_SIZE, HALF_WALL_SIZE,
MAIN_COLOR, SECONDARY_COLOR, cubes, renderer, camera, scene, group
var clock = new THREE.Clock();
clock.start();
var FOV = 45;
_width = window.innerWidth
_height = window.innerHeight
CUBE_SIZE = 80 /* width, height */
GRID = 12 /* cols, rows */
TOTAL_CUBES = (GRID * GRID)
WALL_SIZE = (GRID * CUBE_SIZE)
HALF_WALL_SIZE = (WALL_SIZE / 2)
MAIN_COLOR = 0xFFFFFF
SECONDARY_COLOR = 0x222222
cubes = []
var directions = [];
var normalized = [];
switch(Type) {
case 'WebGL':
renderer = new THREE.WebGLRenderer({antialias: true})
break;
case 'Canvas':
renderer = new THREE.CanvasRenderer({antialias: true})
break;
}
camera = new THREE.PerspectiveCamera(FOV, (_width / _height), 0.1, 10000)
scene = new THREE.Scene()
group = new THREE.Object3D()
/* -- -- */
setupCamera(0, 0, 800)
setupBox(group)
setupFloor(group)
setupCubes(group)
setupLights(group)
group.position.y = 10
group.rotation.set(-60 * (Math.PI/180), 0, -45 * (Math.PI/180))
scene.add(group)
setupRenderer(document.body)
window.addEventListener('resize', resizeHandler, false)
new Input(renderer, camera);
/* -- -- */
function resizeHandler() {
_width = window.innerWidth
_height = window.innerHeight
renderer.setSize(_width, _height)
camera.aspect = _width / _height
camera.updateProjectionMatrix()
}
/* -- CAMERA -- */
function setupCamera(x, y, z) {
camera.position.set(x, y, z)
scene.add(camera)
}
/* -- BOX -- */
function setupBox(parent) {
var i, boxesArray, geometry, material
boxesArray = []
geometry = new THREE.BoxGeometry(WALL_SIZE, WALL_SIZE, 0.05)
geometry.faces[8].color.setHex(SECONDARY_COLOR)
geometry.faces[9].color.setHex(SECONDARY_COLOR)
geometry.colorsNeedUpdate = true
material = new THREE.MeshBasicMaterial({
color : MAIN_COLOR,
vertexColors : THREE.FaceColors,
overdraw: 0.5
})
for (i = 0; i < 5; i++) {
boxesArray.push(new THREE.Mesh(geometry, material))
}
// back
boxesArray[0].position.set(0, HALF_WALL_SIZE, -HALF_WALL_SIZE)
boxesArray[0].rotation.x = 90 * (Math.PI/180)
// right
boxesArray[1].position.set(HALF_WALL_SIZE, 0, -HALF_WALL_SIZE)
boxesArray[1].rotation.y = -90 * (Math.PI/180)
// front
boxesArray[2].position.set(0, -HALF_WALL_SIZE, -HALF_WALL_SIZE)
boxesArray[2].rotation.x = -90 * (Math.PI/180)
// left
boxesArray[3].position.set(-HALF_WALL_SIZE, 0, -HALF_WALL_SIZE)
boxesArray[3].rotation.y = 90 * (Math.PI/180)
// bottom
boxesArray[4].position.set(0, 0, -WALL_SIZE)
boxesArray.forEach(function(box) {
box.renderOrder = 1;
parent.add(box)
});
}
/* -- FLOOR -- */
function setupFloor(parent) {
var i, tilesArray, geometry, material
tilesArray = []
geometry = new THREE.PlaneBufferGeometry(WALL_SIZE, WALL_SIZE)
material = new THREE.MeshLambertMaterial({
color : MAIN_COLOR,
overdraw: 1
})
for (i = 0; i < 8; i++) {
tilesArray.push(new THREE.Mesh(geometry, material))
}
tilesArray[0].position.set(-WALL_SIZE, WALL_SIZE, 0)
tilesArray[1].position.set(0, WALL_SIZE, 0)
tilesArray[2].position.set(WALL_SIZE, WALL_SIZE, 0)
tilesArray[3].position.set(-WALL_SIZE, 0, 0)
tilesArray[4].position.set(WALL_SIZE, 0, 0)
tilesArray[5].position.set(-WALL_SIZE, -WALL_SIZE, 0)
tilesArray[6].position.set(0, -WALL_SIZE, 0)
tilesArray[7].position.set(WALL_SIZE, -WALL_SIZE, 0)
tilesArray.forEach(function(tile) {
tile.receiveShadow = true
tile.renderOrder = 4;
parent.add(tile)
})
}
/* -- CUBES --*/
function setupCubes(parent) {
var i, geometry, material, x, y, row, col
geometry = new THREE.BoxGeometry(CUBE_SIZE, CUBE_SIZE, 0.05)
material = new THREE.MeshPhongMaterial( {
map: new THREE.TextureLoader().load('http://ak.game-socket.de/assets/grass.png'),
normalMap: new THREE.TextureLoader().load('http://ak.game-socket.de/assets/paper_low_nmap.png'),
overdraw: 1,
depthTest: true,
depthWrite: true
} );
x = 0
y = 0
row = 0
col = 0
for (i = 0; i < TOTAL_CUBES; i++) {
cubes.push(new THREE.Mesh(geometry, material))
if ((i % GRID) === 0) {
col = 1
row++
} else col++
x = -(((GRID * CUBE_SIZE) / 2) - ((CUBE_SIZE) * col) + (CUBE_SIZE/2))
y = -(((GRID * CUBE_SIZE) / 2) - ((CUBE_SIZE) * row) + (CUBE_SIZE/2))
cubes[i].position.set(x, y, 0)
}
cubes.forEach(function(cube, index) {
if(index % 2 == 0) {
directions[index] = -1;
normalized[index] = false;
} else {
directions[index] = 1;
normalized[index] = true;
}
cube.castShadow = true
cube.receiveShadow = true
cube.rotation.x = 0;
cube.renderOrder = 3;
cube.doubleSide = true;
parent.add(cube)
})
}
/* -- LIGHTS -- */
function setupLights(parent) {
var light, soft_light
light = new THREE.DirectionalLight(MAIN_COLOR, 1.25)
soft_light = new THREE.DirectionalLight(MAIN_COLOR, 1.5)
light.position.set(-WALL_SIZE, -WALL_SIZE, CUBE_SIZE * GRID)
light.castShadow = true
soft_light.position.set(WALL_SIZE, WALL_SIZE, CUBE_SIZE * GRID)
parent.add(light).add(soft_light)
}
/* -- RENDERER -- */
function setupRenderer(parent) {
renderer.setSize(_width, _height)
renderer.setClearColor(MAIN_COLOR, 1.0);
parent.appendChild(renderer.domElement)
}
var speed = 0.003;
var reach = 40;
function render() {
var delta = clock.getDelta();
requestAnimationFrame(render);
cubes.forEach(function(cube, index) {
cube.castShadow = true
cube.receiveShadow = true
if(directions[index] >= 1) {
++directions[index];
if(directions[index] >= reach) {
directions[index] = -1
}
cube.rotation.x += speed;
} else if(directions[index] <= -1) {
--directions[index];
if(directions[index] <= -reach) {
directions[index] = 1
}
cube.rotation.x -= speed;
}
});
renderer.render(scene, camera)
}
render();
html, body, canvas {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
display: block;
}
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/build/three.min.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/renderers/CanvasRenderer.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/renderers/Projector.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/controls/TrackballControls.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/shaders/ParallaxShader.js"></script>
By option, i don't want, that the rotating/zooming reach the end of the map - The user is not able to look under the map, as example.

How to remove merged Geometry

For performance reasons I merged geometry. I have tens of thousands of cubes to display. I have that working with reasonable performance.
Now I have to deal with removing some. I almost have it but can't figure out how to make this work, so I cut my code up to make this complete sample.
In the onDocumentMouseDown function when a cube is clicked on I try to remove it. And it sort of does. But instead of removing one cube it removes two. (Then it basically acts worse) It removes the one I pointed at and the next one I added.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>Measurement</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<div id="canvas_container" style="position: absolute; left:0px; top:0px; touch-action:none;"></div>
<div id="MessageDisplay1" style="position: absolute; top: 50px; left: 50px; background-color: black; opacity: 0.8; color:white; touch-action:none;"></div>
<div id="MessageDisplay" style="position: absolute; top: 50px; left: 200px; background-color: black; opacity: 0.8; color:white; touch-action:none;"></div>
<script src="js/three.js"></script>
<script>
// player motion parameters
var motioncontrol = {
airborne: false,
bumpposition: 5.0,
bumpdegrees: 4.0,
rotationanglezx: 0,
tiltangle: 0,
distancePointZ : 10000.0,
distancePointY: 100.0,
position : new THREE.Vector3(), velocity : new THREE.Vector3(),
rotation: new THREE.Vector3(), spinning: new THREE.Vector2(),
prevposition : new THREE.Vector3(),
prevrotation : new THREE.Vector3()
};
var mouseDown = 0;
var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var INTERSECTED;
motioncontrol.position.y = 15;
motioncontrol.position.x = 0;
motioncontrol.position.z = 0;
motioncontrol.rotation.x = 0;
motioncontrol.rotation.z = motioncontrol.distancePointZ * Math.cos(0);
motioncontrol.rotation.x = motioncontrol.distancePointZ * Math.sin(0);
motioncontrol.prevposition.copy(motioncontrol.position);
motioncontrol.prevrotation.copy(motioncontrol.rotation);
// Our Javascript will go here.
var domContainer = null;
domContainer = document.getElementById("canvas_container");
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth/window.innerHeight, 0.1, 5000 );
var aspectratio = window.innerWidth/window.innerHeight;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
domContainer.appendChild(renderer.domElement);
var materials = THREE.ImageUtils.loadTexture('texture/sky.jpg');
addEventListener('mousemove', onDocumentMouseMove, false);
domContainer.addEventListener('mousedown', onDocumentMouseDown, false);
domContainer.addEventListener('mouseup', onDocumentMouseUp, false);
var scene = new THREE.Scene();
scene.add(camera);
window.addEventListener('resize', resize, false);
camera.position.x = 0;
camera.position.y = 100;
camera.position.z = -100;
camera.rotation.y = Math.PI / 180.0 * 90;
var directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
directionalLight.position.set(0, -10, 0);
scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff, 3.0);
directionalLight.position.set(0, -50,-1000);
scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff, 3.0);
directionalLight.position.set(0, -50, 1000);
scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff, 3.0);
directionalLight.position.set(-200, -10, 0);
scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff, 3.0);
directionalLight.position.set(200, -10, 0);
scene.add(directionalLight);
addGround(scene);
// array of unsorted geometries.
var CubeGeometryArray = new Array();
var CubeGeometryTier1 = new THREE.Geometry();
var CubeGeometryTier2 = new THREE.Geometry();
var CubeGeometryTier3 = new THREE.Geometry();
var CubeGeometryTier4 = new THREE.Geometry();
var CubeGeometryTier5 = new THREE.Geometry();
// array of materials
var CubeMaterials = new Array();
// array of meshes used for hit testing.
var CubeArray = new Array();
var cMaterialCount = 0;
var Cube20Mesh;
var Cube40Mesh;
var CubesLoaded = false;
LoadCubeMaterial();
LoadCubeMeshs();
var controls;
function resize()
{
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};
function onMouseWheel(event)
{
var delta = 0;
if ( event.wheelDelta !== undefined ) {
// WebKit / Opera / Explorer 9
delta = event.wheelDelta;
} else if ( event.detail !== undefined ) {
// Firefox
delta = - event.detail;
}
if ( delta > 0 ) { // forward
var angle = Math.atan2(motioncontrol.rotation.x, motioncontrol.rotation.z);
motioncontrol.position.z += motioncontrol.bumpposition * Math.cos(angle);
motioncontrol.position.x += motioncontrol.bumpposition * Math.sin(angle);
} else if ( delta < 0 ) {
var angle = Math.atan2(motioncontrol.rotation.x, motioncontrol.rotation.z);
angle += Math.PI;
motioncontrol.position.z += motioncontrol.bumpposition * Math.cos(angle);
motioncontrol.position.x += motioncontrol.bumpposition * Math.sin(angle);
}
};
function onDocumentMouseMove(event)
{
event.preventDefault();
if (mouseDown > 0) {
if (((event.clientX / window.innerWidth) * 2 - 1) > mouse.x) {
motioncontrol.rotationanglezx -= motioncontrol.bumpdegrees;
if (motioncontrol.rotationanglezx < 0)
motioncontrol.rotationanglezx += 360;
var angle = (Math.PI / 180.0) * motioncontrol.rotationanglezx;
motioncontrol.rotation.x = motioncontrol.distancePointZ * Math.cos(angle) - motioncontrol.distancePointZ * Math.sin(angle);
motioncontrol.rotation.z = motioncontrol.distancePointZ * Math.sin(angle) + motioncontrol.distancePointZ * Math.cos(angle);
}
if (((event.clientX / window.innerWidth) * 2 - 1) < mouse.x) {
motioncontrol.rotationanglezx += motioncontrol.bumpdegrees;
if (motioncontrol.rotationanglezx > 360)
motioncontrol.rotationanglezx -= 360;
var angle = (Math.PI / 180.0) * motioncontrol.rotationanglezx;
motioncontrol.rotation.x = motioncontrol.distancePointZ * Math.cos(angle) - motioncontrol.distancePointZ * Math.sin(angle);
motioncontrol.rotation.z = motioncontrol.distancePointZ * Math.sin(angle) + motioncontrol.distancePointZ * Math.cos(angle);
}
}
};
function onDocumentMouseDown(event)
{
++mouseDown;
event.preventDefault();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObjects(CubeArray);
if(intersects.length > 0)
{
if(intersects[0].object.name != null)
{
var offset = intersects[0].object.name * 8;
var offsetfaces = intersects[0].object.name * 12;
var index = intersects[0].object.name;
var selectedObject = scene.getObjectByName("Tier1");
scene.remove(selectedObject);
CubeArray.splice(index, 1);
CubeGeometryTier1 = CubeGeometryArray[0];
CubeGeometryTier1.vertices.splice(offset, 8);
CubeGeometryTier1.faces.splice(offsetfaces, 12);
CubeGeometryTier1.faceVertexUvs[0].splice(offsetfaces, 12);
CubeGeometryArray[0] = CubeGeometryTier1.clone();
CubeGeometryTier1.sortFacesByMaterialIndex();
var cmesh = new THREE.Mesh(CubeGeometryTier1, new THREE.MeshFaceMaterial(CubeMaterials));
cmesh.matrixAutoUpdate = false;
cmesh.updateMatrix();
cmesh.name = "Tier1";
scene.add(cmesh);
}
else
INTERSECTED = null;
}
};
function onDocumentMouseUp(event) {
mouseDown = 0;
event.preventDefault();
}
function addGround(scene1)
{
var materialg = new THREE.MeshBasicMaterial( { color: 0x333333 , side: THREE.BackSide } );
var groundmesh = new THREE.Mesh(new THREE.PlaneGeometry(9000, 4500, 1), materialg);
groundmesh.receiveShadow = true;
groundmesh.rotation.x = Math.PI / 180.0 * 90;
groundmesh.position.set(0, 0, 0);
groundmesh.name = "asphalt";
scene1.add(groundmesh);
};
function writeToScreen(message)
{
var pre = document.getElementById("MessageDisplay");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
}
function writeToScreen2(message)
{
var pre = document.getElementById("MessageDisplay1");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
}
function addCube20(name, x1,z1,azimuth,height,add)
{
var cube;
if (add)
{
if (height > 5)
height = 5;
cube = Cube20Mesh.clone();
cube.visible = true;
cube.receiveShadow = true;
cube.position.set(x1, ((height - 1) * 8.5) + 4.25, z1);
cube.rotation.y = (Math.PI / 180.0) * azimuth;
cube.name = name;
cube.updateMatrix();
AddCubeGeometry(cube.geometry, cube.matrix, height);
cube.matrixWorld = cube.matrix;
CubeArray.push(cube); // kept for hit test
}
};
function addCube40(name, x1, z1, azimuth,height,add)
{
var cube;
if (add)
{
if (height > 5)
height = 1;
cube = Cube40Mesh.clone();
cube.visible = true;
cube.receiveShadow = true;
cube.position.set(x1, ((height - 1) * 8.5) + 4.25, z1);
cube.rotation.y = (Math.PI / 180.0) * azimuth;
cube.name = name;
cube.updateMatrix();
AddCubeGeometry(cube.geometry, cube.matrix, height + 5);
cube.matrixWorld = cube.matrix;
CubeArray.push(cube); // kept for hit test
}
};
function LoadCubeMeshs()
{
var CubeGeometry20 = new THREE.BoxGeometry(20, 8.5, 9.5);
var CubeGeometry40 = new THREE.BoxGeometry(40, 8.5, 9.5);
Cube20Mesh = new THREE.Mesh(CubeGeometry20);
Cube40Mesh = new THREE.Mesh(CubeGeometry40);
CubesLoaded = true;
};
function LoadCubeMaterial()
{
CubeMaterials[0] = new THREE.MeshBasicMaterial({color:0xff0000 });
cMaterialCount++;
CubeMaterials[1] = new THREE.MeshBasicMaterial({color:0xffff00 });
cMaterialCount++;
CubeMaterials[2] = new THREE.MeshBasicMaterial({color:0xffffff });
cMaterialCount++;
CubeMaterials[3] = new THREE.MeshBasicMaterial({color:0x0000ff });
cMaterialCount++;
CubeMaterials[4] = new THREE.MeshBasicMaterial({color:0x00ffff });
cMaterialCount++;
CubeMaterials[5] = new THREE.MeshBasicMaterial({color:0x772255 });
cMaterialCount++;
CubeMaterials[6] = new THREE.MeshBasicMaterial({color:0x552277 });
cMaterialCount++;
CubeMaterials[7] = new THREE.MeshBasicMaterial({color:0x222299 });
cMaterialCount++;
CubeMaterials[8] = new THREE.MeshBasicMaterial({color:0x992222 });
cMaterialCount++;
CubeMaterials[9] = new THREE.MeshBasicMaterial({color:0x000000 });
cMaterialCount++;
};
function DisplayCubes(scene1)
{
if(CubeGeometryTier1.faces.length > 0)
{
var material = new THREE.MeshNormalMaterial();
// save the unsorted geometry.
CubeGeometryArray.push(CubeGeometryTier1.clone());
CubeGeometryTier1.sortFacesByMaterialIndex();
var Cubemesh = new THREE.Mesh(CubeGeometryTier1, new THREE.MeshFaceMaterial(CubeMaterials));
Cubemesh.matrixAutoUpdate = false;
Cubemesh.updateMatrix();
Cubemesh.name = "Tier1";
scene1.add(Cubemesh);
}
if(CubeGeometryTier2.faces.length > 0)
{
// save the unsorted geometry.
CubeGeometryArray.push(CubeGeometryTier2.clone());
// sorting is a HUGE performance boost
CubeGeometryTier2.sortFacesByMaterialIndex();
var Cubemesh = new THREE.Mesh(CubeGeometryTier2, CubeMaterials);
Cubemesh.matrixAutoUpdate = false;
Cubemesh.updateMatrix();
Cubemesh.name = "Tier2";
scene1.add(Cubemesh);
}
if(CubeGeometryTier3.faces.length > 0)
{
CubeGeometryArray.push(CubeGeometryTier3.clone());
CubeGeometryTier3.sortFacesByMaterialIndex();
var Cubemesh = new THREE.Mesh(CubeGeometryTier3, CubeMaterials);
Cubemesh.matrixAutoUpdate = false;
Cubemesh.updateMatrix();
Cubemesh.name = "Tier3";
scene1.add(Cubemesh);
}
if(CubeGeometryTier4.faces.length > 0)
{
CubeGeometryArray.push(CubeGeometryTier4.clone());
CubeGeometryTier4.sortFacesByMaterialIndex();
var Cubemesh = new THREE.Mesh(CubeGeometryTier4, CubeMaterials);
Cubemesh.matrixAutoUpdate = false;
Cubemesh.updateMatrix();
Cubemesh.name = "Tier4";
scene1.add(Cubemesh);
}
if(CubeGeometryTier5.faces.length > 0)
{
CubeGeometryArray.push(CubeGeometryTier5.clone());
CubeGeometryTier5.sortFacesByMaterialIndex();
var Cubemesh = new THREE.Mesh(CubeGeometryTier5, CubeMaterials);
Cubemesh.matrixAutoUpdate = false;
Cubemesh.updateMatrix();
Cubemesh.name = "Tier5";
scene1.add(Cubemesh);
}
};
// merging geometry for improved performance.
function AddCubeGeometry(geom, matrix,tier)
{
switch(tier)
{
case 1:
//CubeGeometryTier1.merge(geom, matrix, tier - 1);
CubeGeometryTier1.merge(geom, matrix);
break;
case 2:
CubeGeometryTier2.merge(geom, matrix,tier - 1);
break;
case 3:
CubeGeometryTier3.merge(geom, matrix,tier - 1);
break;
case 4:
CubeGeometryTier4.merge(geom, matrix,tier - 1);
break;
case 5:
CubeGeometryTier5.merge(geom, matrix,tier - 1);
break;
// forty footers
case 6:
// CubeGeometryTier1.merge(geom, matrix,tier - 1);
CubeGeometryTier1.merge(geom, matrix);
break;
case 7:
CubeGeometryTier2.merge(geom, matrix,tier - 1);
break;
case 8:
CubeGeometryTier3.merge(geom, matrix,tier - 1);
break;
case 9:
CubeGeometryTier4.merge(geom, matrix,tier - 1);
break;
case 10:
CubeGeometryTier5.merge(geom, matrix,tier - 1);
break;
default:
CubeGeometryTier1.merge(geom, matrix,0);
break;
}
};
motioncontrol.position.y = 10;
motioncontrol.position.x = -50;
motioncontrol.position.z = 0;
motioncontrol.rotation.x = 0;
motioncontrol.rotation.z = motioncontrol.distancePointZ * Math.cos(0);
motioncontrol.rotation.x = motioncontrol.distancePointZ * Math.sin(0);
function LoadCubes()
{
var cnt = 0;
for(var x = 0; x < 5; x++)
{
addCube20(cnt, 0, x * 23.0, 90, 1, true);
cnt++;
addCube40(cnt, 10, x * 43, 90, 1, true);
cnt++;
}
};
// game systems code
var keyboardControls = (function() {
var keys = { SP : 32, Q:81, E:69, W : 87, A : 65, S : 83, D : 68, UP : 38, LT : 37, DN : 40, RT : 39 };
var keysPressed = {};
(function( watchedKeyCodes ) {
var handler = function( down ) {
return function( e ) {
var index = watchedKeyCodes.indexOf( e.keyCode );
if( index >= 0 ) {
keysPressed[watchedKeyCodes[index]] = down; e.preventDefault();
}
};
};
window.addEventListener( "keydown", handler( true ), false );
window.addEventListener( "keyup", handler( false ), false );
})([
keys.SP, keys.Q, keys.E, keys.W, keys.A, keys.S, keys.D, keys.UP, keys.LT, keys.DN, keys.RT
]);
return function() {
// look around
if (keysPressed[keys.Q])
{
motioncontrol.tiltangle += motioncontrol.bumpdegrees;
if (motioncontrol.tiltangle < 0)
motioncontrol.tiltangle += 360;
var angle = (Math.PI / 180.0) * motioncontrol.tiltangle;
motioncontrol.rotation.y = motioncontrol.distancePointZ * Math.sin(angle);
}
if (keysPressed[keys.E])
{
motioncontrol.tiltangle -= motioncontrol.bumpdegrees;
if (motioncontrol.tiltangle < 0)
motioncontrol.tiltangle += 360;
var angle = (Math.PI / 180.0) * motioncontrol.tiltangle;
motioncontrol.rotation.y = motioncontrol.distancePointZ * Math.sin(angle);
}
if (keysPressed[keys.W])
{
motioncontrol.position.y += motioncontrol.bumpposition;
if (motioncontrol.position.y > 1000.0)
motioncontrol.position.y = 1000.0;
}
if (keysPressed[keys.S])
{
motioncontrol.position.y += -motioncontrol.bumpposition;
if (motioncontrol.position.y < 1.0)
motioncontrol.position.y = 1;
}
if(keysPressed[keys.A])
{
var angle = Math.atan2(motioncontrol.rotation.x, motioncontrol.rotation.z);
angle += Math.PI / 180.0 * 90;
var message = "Angle " + angle * 180/Math.PI;
motioncontrol.position.z += motioncontrol.bumpposition * Math.cos(angle);
motioncontrol.position.x += motioncontrol.bumpposition * Math.sin(angle);
}
if(keysPressed[keys.D])
{
var angle = Math.atan2(motioncontrol.rotation.x, motioncontrol.rotation.z);
angle += Math.PI / 180.0 * -90;
var message = "Angle " + angle * 180/Math.PI;
motioncontrol.position.z += motioncontrol.bumpposition * Math.cos(angle);
motioncontrol.position.x += motioncontrol.bumpposition * Math.sin(angle);
}
// forward
if (keysPressed[keys.UP])
{
var angle = Math.atan2(motioncontrol.rotation.x, motioncontrol.rotation.z);
var message = "Angle " + angle * 180/Math.PI;
motioncontrol.position.z += motioncontrol.bumpposition * Math.cos(angle);
motioncontrol.position.x += motioncontrol.bumpposition * Math.sin(angle);
}
// backward
if(keysPressed[keys.DN])
{
var deltaX = motioncontrol.rotation.z - motioncontrol.position.z;
var deltaY = motioncontrol.rotation.x - motioncontrol.position.x;
// var angle = Math.atan2(deltaY, deltaX);
var angle = Math.atan2(motioncontrol.rotation.x, motioncontrol.rotation.z);
angle += Math.PI;
var message = "Angle " + angle * 180/Math.PI;
motioncontrol.position.z += motioncontrol.bumpposition * Math.cos(angle);
motioncontrol.position.x += motioncontrol.bumpposition * Math.sin(angle);
}
if(keysPressed[keys.LT])
{
motioncontrol.rotationanglezx -= motioncontrol.bumpdegrees;
if (motioncontrol.rotationanglezx < 0)
motioncontrol.rotationanglezx += 360;
var angle = (Math.PI / 180.0) * motioncontrol.rotationanglezx;
motioncontrol.rotation.x = motioncontrol.distancePointZ * Math.cos(angle) - motioncontrol.distancePointZ * Math.sin(angle);
motioncontrol.rotation.z = motioncontrol.distancePointZ * Math.sin(angle) + motioncontrol.distancePointZ * Math.cos(angle);
}
if(keysPressed[keys.RT])
{
motioncontrol.rotationanglezx += motioncontrol.bumpdegrees;
if (motioncontrol.rotationanglezx > 360)
motioncontrol.rotationanglezx -= 360;
var angle = (Math.PI / 180.0) * motioncontrol.rotationanglezx;
motioncontrol.rotation.x = motioncontrol.distancePointZ * Math.cos(angle) - motioncontrol.distancePointZ * Math.sin(angle);
motioncontrol.rotation.z = motioncontrol.distancePointZ * Math.sin(angle) + motioncontrol.distancePointZ * Math.cos(angle);
}
};
})();
var updateCamera = (function() {
return function() {
camera.position.copy(motioncontrol.position);
camera.lookAt(motioncontrol.rotation);
var message = "Rotation " + motioncontrol.rotationanglezx + "<BR>";
message += "X " + motioncontrol.position.x + "<BR>";
message += "Y " + motioncontrol.position.y + "<BR>";
message += "Z " + motioncontrol.position.z + "<BR>";
message += "X " + motioncontrol.rotation.x + "<BR>";
message += "Y " + motioncontrol.rotation.y + "<BR>";
message += "Z " + motioncontrol.rotation.z + "<BR>";
var angle = Math.atan2(motioncontrol.rotation.x, motioncontrol.rotation.z);
message += "Angle " + angle * 180 / Math.PI + "<BR>";
message += "Use Arrows w,s,e,d,q,a to navigate<BR>";
writeToScreen2(message);
};
})();
function render() {
if(cMaterialCount > 9 && cMaterialCount < 200 && CubesLoaded)
{
cMaterialCount = 200;
LoadCubes();
DisplayCubes(scene);
}
keyboardControls();
updateCamera();
renderer.render( scene, camera );
requestAnimationFrame( render );
};
render();
</script>
</body>
</html>
TLDR Array Mutation and Static Offsets are a dangerous mix
First, I recommend you post fiddles of some sort of your code. I made one here of your example. Second, you could really use some DRYing to shorten and clarify your code. Third, in code of this size, I recommend separating and grouping your code somehow (files, tasks, even comment blocks). Last, in a demo like this, I see no reason to roll your own controls. Check out Orbit Camera or the like that THREE.js offers.
Anyway, I gathered you collect a large number of cubes into 10 'tiers' of THREE.Geometry for rendering purposes. Then on click (~line 180), raycast out, and try to remove just that cube from the geometry. Here's your relevant code:
intersects = raycaster.intersectObjects(CubeArray);
if(intersects.length > 0)
{
if(intersects[0].object.name != null)
{
var offset = intersects[0].object.name * 8;
var offsetfaces = intersects[0].object.name * 12;
var index = intersects[0].object.name;
var selectedObject = scene.getObjectByName("Tier1");
scene.remove(selectedObject);
CubeArray.splice(index, 1);
CubeGeometryTier1 = CubeGeometryArray[0];
CubeGeometryTier1.vertices.splice(offset, 8);
CubeGeometryTier1.faces.splice(offsetfaces, 12);
CubeGeometryTier1.faceVertexUvs[0].splice(offsetfaces, 12);
CubeGeometryArray[0] = CubeGeometryTier1.clone();
CubeGeometryTier1.sortFacesByMaterialIndex();
var cmesh = new THREE.Mesh(CubeGeometryTier1, new THREE.MeshFaceMaterial(CubeMaterials));
cmesh.matrixAutoUpdate = false;
cmesh.updateMatrix();
cmesh.name = "Tier1";
scene.add(cmesh);
}
else
INTERSECTED = null;
}
Here's how I read this snippet:
Cast out against the CubeArray
Without a hit something or if it lacks a name, return
Implict cast some string names (!) to numbers to compute location in Tier
Remove an object from the scene by the name "Tier1", regardless of any other input
Set CubeGeometryTier1 to the first index of CubeGeometryArray, regardless of raycast
Fiddle with now overwritten CubeGeometryTier1 to remove geometry
Reassign CubeGeometryArray[0] with the changed object of CubeGeometryTier1
Build a new mesh based on CubeGeometryTier1, call it "Tier1" and dump it back into the scene
I'll admit I haven't entirely traced the hundreds of line where you build your cubes, but this makes little sense to me. Assuming your use of CubeGeometry[Tier|Array] and hard coded names and indices are correct, what really grabs me is the use of static offsets when you mutate the array.
You splice CubeArray to remove that 'ghost' cube from getting picked again, but none of the other 'ghost' cubes changed, notably their offsets names, while the geometry that you rebuilt into Tier1 did. Past the spliced cube, all of them index names will be wrong.
Here's an example in simpler form:
//set up
var baseArray = [0, 1, 2, 3, 4, 5].map(i => '' + i);
const getRandomInt = (min, max) => {
return Math.floor(Math.random() * (max - min)) + min;
};
const pickRandomElementFrombaseArray = () => {
const pickedIndex = getRandomInt(0, baseArray.length);
return baseArray[pickedIndex];
};
// operationally equivilent to splicing your Tiers of their geometry
const yankIndex = (value) => {
//value is a string in this case
const index = +value;
if (index < 0 || index > baseArray.length - 1) {
throw `Unable to remove invalid index ${index}`
} else {
baseArray.splice(index, 1);
}
};
// Run the test until empty or failure
var messages = [`Starting with ${baseArray}`];
while (baseArray.length > 0) {
const pickedValue = pickRandomElementFrombaseArray();
messages.push(`Picked element ${pickedValue} to remove`);
try {
yankIndex(pickedValue);
messages.push(`Now array is ${baseArray}`);
} catch (e) {
messages.push(`ALERT: ${e}`);
break;
}
}
messages.push('Test complete');
const div = $('#div');
messages.map(msg => `<p>${msg}</p>`).forEach(msg => div.append(msg))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
</head>
<body>
<h2>Results</h2>
<div id="div"></div>
</body>
</html>
Try it a few times. There's only a 0.8% chance the array will be exhausted before an error.
Sneaky errors can creep into code when you are dealing with mutation of arrays. Ignoring restructuring the code entirely, options that spring to mind:
Maintain an offset map on each removal. Essentially, rebuild each cube's offset on every action. You could do this in the CubeArray or, if creating/mutating 10k heavy THREE.js objects is not to your liking, yet another level of indirection that maps each cube id to an offset in the Tiers
Invisible Objects Never really remove the geometry (ie, don't splice the Tier array), just hide it. Scale the faces to 0, invisible mat, whatever. This means all the offsets you pre-generate will hold. Downsides are invisible geo isn't free, this won't help if you need to change the scene in other ways, and you'll have to scan the other hits from thee.raycast

Prevent objects from moving outside room in three js

I have created a room in three js and added various objects in it. But,
the objects are moving out of the room. Here is the url on which my code is running:
http://istation-demo.cladev.com/room.html
In order to prevent objects leaving the room or colliding with each other, you must have at least a simple form of collision detection. Most 3D engines, three.js included, have Axis-Aligned Bounding Boxes ( or AABB ) for all the 3d objects that are created. In three.js to get access to bounding boxes, the easiest way is to call
var boundingBoxHelperObject = new THREE.BoundingBoxHelper( object )
If you add it to the scene, it shows up as a wireframe grey box that fits tightly around the object. If you call update on the helper (as you will see shortly), it will update to the dimensions and movement of the 3d object in real time - pretty cool!
Then, to perform collision detection on all these boxes, you call
boundingBoxHelperObject.box.intersectsBox( anotherBoxHelperObject.box )
which outputs true if colliding or false if not colliding. Then perform the appropriate actions, such as moving the box back a frame to prevent it from escaping a room or penetrating another solid object, or changing both colliding objects' colors, or whatever you want.
Here's the final code sample with my corrected picking/dragging code from the last post you made months ago, plus the new bounding boxes and collision testing code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head lang="en">
<meta charset="UTF-8">
<title>Room</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/OBJLoader.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/MTLLoader.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/OBJMTLLoader.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="workspace"></div>
<script>
//define global variables here
var container, renderer;
var camera, scene, projector, mouseVector, controls;
var mouseX, mouseY, draggable;
var pen, c_mesh, interactiveObj = [], rotateObj = [], groundRaycastObj = [];
var wallWidth = 1200;
var wallHeight = 400;
var chair_model, sofa_model;
var chair_selected = false;
var sofa_selected = false;
var raycaster;
var mouse = new THREE.Vector2(), INTERSECTED;
var radius = 100, theta = 0;
var oldIntersectPoint = new THREE.Vector3();
var newIntersectPoint = new THREE.Vector3();
var intersectOffset = new THREE.Vector3();
var chairOldPosition = new THREE.Vector3();
var sofaOldPosition = new THREE.Vector3();
var chair_rotate = false;
var walls;
var mesh_box;
var wallright, wallleft, wallback, wallfront, ceiling, ground;
var strDownloadMime = "image/octet-stream";
var chairBox, sofaBox;
var wallrightBox, wallleftBox, wallbackBox, wallfrontBox;
init();
animate();
function init() {
container = document.getElementById('workspace'); //document.createElement('div');
document.body.appendChild(container);
//camera
//camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 10, 10000);
// camera.position.set(0, -wallHeight / 2 + 10, wallWidth);
// camera.lookAt(new THREE.Vector3(10, 10, 10));
//renderer
renderer = new THREE.WebGLRenderer({preserveDrawingBuffer: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x889988);
renderer.shadowMapEnabled = true;
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
raycaster = new THREE.Raycaster();
var ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z= wallWidth;
camera.position.y= wallWidth/2;
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.25;
//controls.enableZoom = false;
//walls
walls = new THREE.Object3D();
var groundGeo_2 = new THREE.PlaneGeometry(wallWidth, wallWidth); //for roof and floor
var groundGeo = new THREE.PlaneGeometry(wallWidth, wallHeight);
var wallTextureRight = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg')
});
wallTextureRight.map.needsUpdate = true;
var wallTextureLeft = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg')
});
var wallTextureFront = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg')
});
var wallTextureBack = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/wall3.png')
});
var floorTexture = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/floor.jpg')
});
floorTexture.map.needsUpdate = true;
var ceilTexture = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg')
});
ground = new THREE.Mesh(groundGeo_2, floorTexture);
ground.overdraw = true;
ground.position.set(0, 0, 0);
ground.rotation.x = -Math.PI / 2;
walls.add(ground);
console.log(ground);
wallleft = new THREE.Mesh(groundGeo, wallTextureLeft);
wallleft.overdraw = true;
wallleft.position.set(-wallWidth / 2, wallHeight / 2, 0);
wallleft.rotation.y = Math.PI / 2;
walls.add(wallleft);
wallleftBox = new THREE.BoundingBoxHelper( wallleft );
wallleftBox.update(wallleft);
//wallleftBox.box.min.x -= 0.1;
//wallleftBox.box.max.x += 0.1;
//scene.add(wallleftBox);
wallright = new THREE.Mesh(groundGeo, wallTextureRight);
wallright.overdraw = true;
wallright.position.set(wallWidth / 2, wallHeight / 2, 0);
wallright.rotation.y = -Math.PI / 2;
walls.add(wallright);
wallrightBox = new THREE.BoundingBoxHelper( wallright );
wallrightBox.update(wallright);
//wallrightBox.box.min.x -= 0.1;
//wallrightBox.box.max.x += 0.1;
//scene.add(wallrightBox);
wallback = new THREE.Mesh(groundGeo, wallTextureBack);
wallback.overdraw = true;
wallback.position.set(0, wallHeight / 2, -wallWidth / 2);
walls.add(wallback);
wallbackBox = new THREE.BoundingBoxHelper( wallback );
wallbackBox.update(wallback);
//scene.add(wallbackBox);
wallfront = new THREE.Mesh(groundGeo, wallTextureFront);
wallfront.overdraw = true;
wallfront.position.set(0, wallHeight / 2, wallWidth / 2);
wallfront.rotation.y = -Math.PI;
walls.add(wallfront);
wallfrontBox = new THREE.BoundingBoxHelper( wallfront );
wallfrontBox.update(wallfront);
//scene.add(wallfrontBox);
ceiling = new THREE.Mesh(groundGeo_2, ceilTexture);
ceiling.position.set(0, wallHeight, 0);
ceiling.rotation.x = Math.PI / 2;
walls.add(ceiling);
scene.add(walls);
groundRaycastObj.push(walls);
//load bed texture
var bed_texture = new THREE.ImageUtils.loadTexture("textures/cb-rochelle-gray_baked.png");
var bedMaterial = new THREE.MeshBasicMaterial({
map: bed_texture,
side: THREE.DoubleSide
});
//load bed
var loader = new THREE.JSONLoader();
loader.load('js/sofa.js', function (geometry) {
sofa_model = new THREE.Mesh(geometry, bedMaterial);
for (var i = 0; i < sofa_model.children.length; i++) {
sofa_model.children[i].material = material;
sofa_model.children[i].userDataParent = sofa_model;
sofa_model.children[i].name = 'sofa_model';
}
sofa_model.position.set(200,0, -200);
sofa_model.rotation.set(0, 0, 0);
sofa_model.scale.set(3, 3, 3);
sofa_model.name = 'sofa_model';
interactiveObj.push(sofa_model);
scene.add(sofa_model);
sofaBox = new THREE.BoundingBoxHelper( sofa_model );
// comment next line out if you don't want to see the wireframe sofa boxHelper
scene.add(sofaBox);
});
//load chair texture
var chair_texture = new THREE.ImageUtils.loadTexture("textures/chair.png");
var chairMaterial = new THREE.MeshBasicMaterial({
map: chair_texture,
side: THREE.DoubleSide
});
//load chair
var loader = new THREE.JSONLoader();
loader.load('js/chair_model.js', function (geometry) {
chair_model = new THREE.Mesh(geometry, chairMaterial);
for (var i = 0; i < chair_model.children.length; i++) {
chair_model.children[i].material = material;
chair_model.children[i].userDataParent = sofa_model;
chair_model.children[i].name = 'chair_model';
}
chair_model.position.set(-300,0, -200);
chair_model.rotation.set(0, 0, 0);
chair_model.scale.set(3, 3, 3);
chair_model.name = 'chair_model';
interactiveObj.push(chair_model);
scene.add(chair_model);
chairBox = new THREE.BoundingBoxHelper( chair_model );
// comment next line out if you don't want to see the wireframe chair boxHelper
scene.add(chairBox);
});
//IE, Chrome, Safari, Opera
document.addEventListener('mousewheel', onDocumentMouseWheel, false);
//Firefox
document.addEventListener('DOMMouseScroll', onDocumentMouseWheel, false);
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
window.addEventListener('resize', onWindowResize, false);
}
function animate() {
requestAnimationFrame(animate);
chair_model.rotation.y += 0.02;
chairBox.update(chair_model);
sofaBox.update(sofa_model);
//wallrightBox.update(wallright);
//wallleftBox.update(wallleft);
//wallfrontBox.update(wallfront);
//wallbackBox.update(wallback);
controls.update();
// Render the frame
//Don't render twice, it will slow down your animation!
//render();
renderer.render(scene, camera);
}
function render() {
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
//controls.handleResize();
}
function onDocumentMouseDown(event) {
draggable = true;
event.preventDefault();
var testIntersects;
testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
if (testIntersects.length > 0)
oldIntersectPoint.copy(testIntersects[0].point);
// find intersections
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(interactiveObj, true);
if (intersects.length > 0) {
controls.enabled=false;
if (intersects[0].object.name == 'chair_model') {
container.style.cursor = 'pointer';
chair_selected = true;
//oldIntersectPoint.copy(chair_model.position);
chairBox.material.color.set('white');
} else if (intersects[0].object.name == 'sofa_model') {
container.style.cursor = 'pointer';
sofa_selected = true;
//oldIntersectPoint.copy(sofa_model.position);
sofaBox.material.color.set('white');
}
else {
chair_selected = false;
sofa_selected = false;
}
draggable = false;
}
}
function onDocumentMouseUp(event) {
draggable = false;
chair_selected = false;
sofa_selected = false;
chair_rotate = false;
container.style.cursor = 'auto';
controls.enabled=true;
oldIntersectPoint.set(0,0,0);
newIntersectPoint.set(0,0,0);
intersectOffset.set(0,0,0);
chairBox.material.color.set('grey');
sofaBox.material.color.set('grey');
}
function onDocumentMouseMove(event) {
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
var deltaX = event.clientX - mouseX;
var deltaY = event.clientY - mouseY;
var testIntersects;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(interactiveObj, true);
if (intersects.length > 0) {
container.style.cursor = 'pointer';
//addRotationLine(intersects[0].object);
} else {
container.style.cursor = 'auto';
}
if (draggable) {
} else if (chair_selected == true) {
testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
if (testIntersects.length > 0) {
var okToMove = true;
chairOldPosition.copy(chair_model.position);
newIntersectPoint.copy(testIntersects[0].point);
intersectOffset.copy(newIntersectPoint);
intersectOffset.sub(oldIntersectPoint);
//uncomment below if you want more precision mouse movements of objects
//intersectOffset.multiplyScalar(0.1);
// store old intersect point for next frame
oldIntersectPoint.copy(newIntersectPoint);
chair_model.position.add(intersectOffset);
chair_model.updateMatrixWorld(true);
//chairBox.updateMatrixWorld(true);
chairBox.update(chair_model);
// default
chairBox.material.color.set('white');
if( chairBox.box.intersectsBox(sofaBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallrightBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallleftBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallfrontBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallbackBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
// if NOT ok to move and chair is hitting something,
if ( !okToMove ) {
// put chair back where it was
chair_model.position.copy(chairOldPosition);
}
}
// clamp chair position to the ground
chair_model.position.y = 0;
} else if (chair_rotate == true) {
rotate_object(chair_model, event);
}
else if (sofa_selected == true) {
testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
if (testIntersects.length > 0) {
var okToMove = true;
sofaOldPosition.copy(sofa_model.position);
newIntersectPoint.copy(testIntersects[0].point);
intersectOffset.copy(newIntersectPoint);
intersectOffset.sub(oldIntersectPoint);
//uncomment below if you want more precision mouse movements of objects
//intersectOffset.multiplyScalar(0.1);
oldIntersectPoint.copy(newIntersectPoint);
sofa_model.position.add(intersectOffset);
sofa_model.updateMatrixWorld(true);
//sofaBox.updateMatrixWorld(true);
sofaBox.update(sofa_model);
// default
sofaBox.material.color.set('white');
if( sofaBox.box.intersectsBox(chairBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallrightBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallleftBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallfrontBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallbackBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
// if NOT ok to move and sofa is hitting something,
if ( !okToMove ) {
// put sofa back where it was
sofa_model.position.copy(sofaOldPosition);
}
}
// clamp sofa position to the ground
sofa_model.position.y = 0;
}
mouseX = event.clientX;
mouseY = event.clientY;
//render(); // no need to render
}
function onDocumentMouseWheel(event) {
// This is automatically handled for you by orbitControls.js,
// but you can't disable zoom on the controls - so don't type controls.enableZoom = false;
//mouseDelta = (-event.wheelDeltaY || event.detail);
//camera.position.z += mouseDelta * 1;
//render(); // no need to render
}
function addRotationLine(objModel) {
var material = new THREE.LineBasicMaterial({
color: 0x0000ff,
linewidth: 6
});
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(-10, 500, 0),
new THREE.Vector3(1000, 500, 0)
);
var line = new THREE.Line(geometry, material);
objModel.add(line);
}
function rotate_object(object, event) {
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
var deltaX = event.clientX - mouseX;
var deltaY = event.clientY - mouseY;
object.rotation.y += deltaX * 0.02;
object.rotation.y += deltaY * 0.01;
}
</script>
</body>
</html>
Hope this works for you! :)

Threejs Sprite raycasting not consistent

I'm experiencing very poor raycasting results on sprites. I would say that it works best when the sprites are centred but then activation is not consistent on subsequent events.
var touchCounter=0;
function onDocumentMouseDown( event )
{
touchCounter ++;
$('#footer .social h2').text("event " + touchCounter);
// update the mouse variable
mouse.x = ( ( event.clientX - renderer.domElement.offsetLeft ) / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( ( event.clientY - renderer.domElement.offsetTop ) / renderer.domElement.height ) * 2 + 1;
mouse.z = 0.75;
Raycasting();
}
function onDocumentTouchStart( event )
{
touchCounter ++;
$('#footer .social h2').text("event " + touchCounter);
if ( event.touches.length == 1 ) {
event.preventDefault();
mouse.x = ( ( event.targetTouches[0].pageX - renderer.domElement.offsetLeft ) / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( ( event.targetTouches[0].pageY - renderer.domElement.offsetTop ) / renderer.domElement.height ) * 2 + 1;
mouse.z = 0.75;
Raycasting();
}
}
function Raycasting() {
var ray = new THREE.Raycaster( camera.position, mouse.sub( camera.position ).normalize() );
var intersects = ray.intersectObjects( targetList );
if ( intersects.length > 0 )
{
if ( intersects[ 0 ].object != INTERSECTED )
{
if ( INTERSECTED )
INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
$('#footer .social h2').text("event " + touchCounter + " and hit");
controls.autoRotate = false;
modal.show();
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
INTERSECTED.material.color.setHex( 0xffff00 );
}
}
else // there are no intersections
{
controls.autoRotate = true;
modal.hide();
if ( INTERSECTED )
INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
}
}
The targetList array the current sprites...
var spriteList = new Array(
"solar",
"wind",
"water");
var spriteMaterial;
for (var i = 0; i < spriteList.length; i++) {
spriteMaterial = THREE.ImageUtils.loadTexture( "assets/models/home/sprites/" + spriteList[i] + ".png", undefined, createHUDSprites );
}
var ind = 0;
function createHUDSprites ( spriteMaterial ) {
var material = new THREE.SpriteMaterial( { map: spriteMaterial } );
var sprite = new THREE.Sprite( material );
var multi = 0.12;
sprite.scale.set( material.map.image.width*multi, material.map.image.height*multi, 1 );
switch(ind) {
case 0:
sprite.position.set(-60,20,-18); //solar
targetList.push(sprite);
break;
case 1:
sprite.position.set(-20,-42,-35); //wind
targetList.push(sprite);
break;
case 2:
sprite.position.set(-20,42,50); //water
targetList.push(sprite);
break;
case 3:
sprite.position.set(50,14,45); //shelter
targetList.push(sprite);
break;
case 4:
sprite.position.set(50,22,-25); //utilities
targetList.push(sprite);
break;
case 5:
sprite.position.set(45,-24,50); //telescope
multi = 0.05;
sprite.scale.set( material.map.image.width*multi, material.map.image.height*multi, 1 );
targetList.push(sprite);
break;
case 6:
sprite.position.set(40,42,-20); //utilities
multi = 0.05;
sprite.scale.set( material.map.image.width*multi, material.map.image.height*multi, 1 );
targetList.push(sprite);
break;
case 7:
sprite.position.set(-40,-5,-50); //utilities
multi = 0.05;
sprite.scale.set( material.map.image.width*multi, material.map.image.height*multi, 1 );
targetList.push(sprite);
break;
default:
sprite.position.set(-20,-42,-35);
console.log("Problem loading sprites");
}
ind++;
scene.add( sprite );
} //end createHudSprites()
Maybe an issue with scaling? or how Im instantiating the THREE.Raycaster object?
You can see an example of my site here http://earthscool.com.au
Threejs R72
Set the ray as global
var ray = new THREE.Raycaster();
Then set the ray as found in the docs
function Raycasting() {
ray.setFromCamera( mouse, camera );
...
Also add proper event handlers as per doc... this one for touch devices
mouse.x = ( event.targetTouches[0].pageX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.targetTouches[0].pageY / window.innerHeight ) * 2 + 1;
mouse.z = 0.5;

Reset camera using OrbitControls.js

I'm using OrbitControls.js to allow mouse interaction. I'm adding a button into the scene that allows to "reset" the camera to it's state where it was before any mouse interactions.
I have tried to save camera.position and camera.rotation before any interactions:
camera_initial_position = camera.position;
camera_initial_rotation = camera.rotation;
And after the "reset" button is pressed, the initial position and rotation is set:
camera.position = camera_initial_position;
camera.rotation = camera_initial_rotation;
It works well if pan is not used. If user pans using mouse right button, then the above code cannot "reset" camera.
What is the right method to "reset" the camera to its previous state?
Revision of three.js is r58 and this is the OrbitControls.js:
/**
* #author qiao / https://github.com/qiao
* #author mrdoob / http://mrdoob.com
* #author alteredq / http://alteredqualia.com/
* #author WestLangley / http://github.com/WestLangley
*/
THREE.OrbitControls = function ( object, domElement ) {
this.object = object;
this.domElement = ( domElement !== undefined ) ? domElement : document;
// API
this.enabled = true;
this.center = new THREE.Vector3();
this.userZoom = true;
this.userZoomSpeed = 1.0;
this.userRotate = true;
this.userRotateSpeed = 1.0;
this.userPan = true;
this.userPanSpeed = 2.0;
this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
this.minDistance = 0;
this.maxDistance = Infinity;
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
// internals
var scope = this;
var EPS = 0.000001;
var PIXELS_PER_ROUND = 1800;
var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var zoomStart = new THREE.Vector2();
var zoomEnd = new THREE.Vector2();
var zoomDelta = new THREE.Vector2();
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var lastPosition = new THREE.Vector3();
var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2 };
var state = STATE.NONE;
// events
var changeEvent = { type: 'change' };
this.rotateLeft = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
thetaDelta -= angle;
};
this.rotateRight = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
thetaDelta += angle;
};
this.rotateUp = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
phiDelta -= angle;
};
this.rotateDown = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
phiDelta += angle;
};
this.zoomIn = function ( zoomScale ) {
if ( zoomScale === undefined ) {
zoomScale = getZoomScale();
}
scale /= zoomScale;
};
this.zoomOut = function ( zoomScale ) {
if ( zoomScale === undefined ) {
zoomScale = getZoomScale();
}
scale *= zoomScale;
};
this.pan = function ( distance ) {
distance.transformDirection( this.object.matrix );
distance.multiplyScalar( scope.userPanSpeed );
this.object.position.add( distance );
this.center.add( distance );
};
this.update = function () {
var position = this.object.position;
var offset = position.clone().sub( this.center );
// angle from z-axis around y-axis
var theta = Math.atan2( offset.x, offset.z );
// angle from y-axis
var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
if ( this.autoRotate ) {
this.rotateLeft( getAutoRotationAngle() );
}
theta += thetaDelta;
phi += phiDelta;
// restrict phi to be between desired limits
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
// restrict phi to be betwee EPS and PI-EPS
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
var radius = offset.length() * scale;
// restrict radius to be between desired limits
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
offset.y = radius * Math.cos( phi );
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
position.copy( this.center ).add( offset );
this.object.lookAt( this.center );
thetaDelta = 0;
phiDelta = 0;
scale = 1;
if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
this.dispatchEvent( changeEvent );
lastPosition.copy( this.object.position );
}
};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow( 0.95, scope.userZoomSpeed );
}
function onMouseDown( event ) {
if ( scope.enabled === false ) return;
if ( scope.userRotate === false ) return;
event.preventDefault();
if ( event.button === 0 ) {
state = STATE.ROTATE;
rotateStart.set( event.clientX, event.clientY );
} else if ( event.button === 1 ) {
state = STATE.ZOOM;
zoomStart.set( event.clientX, event.clientY );
} else if ( event.button === 2 ) {
state = STATE.PAN;
}
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
}
function onMouseMove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
if ( state === STATE.ROTATE ) {
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart );
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed );
scope.rotateUp( 2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed );
rotateStart.copy( rotateEnd );
} else if ( state === STATE.ZOOM ) {
zoomEnd.set( event.clientX, event.clientY );
zoomDelta.subVectors( zoomEnd, zoomStart );
if ( zoomDelta.y > 0 ) {
scope.zoomIn();
} else {
scope.zoomOut();
}
zoomStart.copy( zoomEnd );
} else if ( state === STATE.PAN ) {
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
scope.pan( new THREE.Vector3( - movementX, movementY, 0 ) );
}
}
function onMouseUp( event ) {
if ( scope.enabled === false ) return;
if ( scope.userRotate === false ) return;
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
state = STATE.NONE;
}
function onMouseWheel( event ) {
if ( scope.enabled === false ) return;
if ( scope.userZoom === false ) return;
var delta = 0;
if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta;
} else if ( event.detail ) { // Firefox
delta = - event.detail;
}
if ( delta > 0 ) {
scope.zoomOut();
} else {
scope.zoomIn();
}
}
function onKeyDown( event ) {
if ( scope.enabled === false ) return;
if ( scope.userPan === false ) return;
switch ( event.keyCode ) {
case scope.keys.UP:
scope.pan( new THREE.Vector3( 0, 1, 0 ) );
break;
case scope.keys.BOTTOM:
scope.pan( new THREE.Vector3( 0, - 1, 0 ) );
break;
case scope.keys.LEFT:
scope.pan( new THREE.Vector3( - 1, 0, 0 ) );
break;
case scope.keys.RIGHT:
scope.pan( new THREE.Vector3( 1, 0, 0 ) );
break;
}
}
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
this.domElement.addEventListener( 'keydown', onKeyDown, false );
};
THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
You can reset the camera when using OrbitControls like so:
controls.reset();
three.js r.71
Pan operation is updating vector called this.center , you need to reset it to see pan method ,
this.center.add( distance );
set this method to:
this.resetCamera = function ( ) {
this.object.position.x= camera_initial_position.xPosition;
this.object.position.y = camera_initial_position.yPosition;
this.object.position.z = camera_initial_position.zPosition;
this.center.x= camera_initial_target.x;
this.center.y= camera_initial_target.y;
this.center.z= camera_initial_target.z;
};
and then the update method will keep the camera looking at the center vector.
ah.adel is correct Pan operation will update the center of the camera controller. Therefore if you need to reset/restore the camera to a predefined camera, you need to set camera controller center also.
Following code is a simple code to store camera position, rotation and control center
var camToSave = {};
camToSave.position = camera.position.clone();
camToSave.rotation = camera.rotation.clone();
camToSave.controlCenter = controls.target.clone();
Use this function to restore camera later.
function restoreCamera(position, rotation, controlCenter){
camera.position.set(position.x, position.y, position.z);
camera.rotation.set(rotation.x, rotation.y, rotation.z);
controls.target.set(controlCenter.x, controlCenter.y, controlCenter.z);
controls.update();
render();
}
Call restoreCamera function to restore saved camera.
restoreCamera(camToSave.position, camToSave.rotation, camToSave.controlCenter);
Hope this will help to anyone who having this problem

Resources