Related
I have written code that works perfectly when i run it locally on my system.
This is the link:
https://jsfiddle.net/rand0mus3r/L3j7kz5a/
When you click the mesh, a dat.gui instance appears. However, when i use backspace or try to input something in the textbox, it doesn't work.
It works fine in my system though.
This is the code:
<!DOCTYPE html>
<html>
<head>
<title>Example 01.02 - First Scene</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/OrbitControls.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>
</body>
</html>
window.onload = init();
animate(); //calling function that does all the rendering
//GLOBAL VARS
var scene, camera, renderer;
var cube;
var raycaster, mouse;
var INTERSECTED;
//global flag
var isClicked = false;
//for the camera
var controls;
//creating and rendering the GUI
params = {
yAxis: "0.00001"
}
var gui = new dat.GUI();
gui.add(params, "yAxis").onFinishChange(val => {
cube.scale.y = parseFloat(val);
});
//we make sure to make it hidden
let vis = gui.domElement.style.visibility;
gui.domElement.style.visibility = vis == "" ? "hidden" : "";
// once everything is loaded, we run our Three.js stuff.
function init() {
// create a scene, that will hold all our elements such as objects, cameras and lights.
scene = new THREE.Scene();
//SET CAMERA
camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)
camera.position.z = 5;
// create a render and set the size
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor("#e5e5e5"); //background color
renderer.setSize(window.innerWidth,window.innerHeight); //size of renderer
//bind rendered to the dom element
document.getElementById("WebGL-output").appendChild(renderer.domElement);
//RAYCASTER
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2(1,1);
// create a cube
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xffff00 }); //0xF7F7F7 = gray
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.scale.y = 0.00001;
cube.userData.originalColor = 0xffff00;
// position the cube
cube.position.x = 0;
cube.position.y = 3;
cube.position.z = 0;
/*
//USEFUL METHODS
cube.rotation.x +=0.5
cube.scale.x +=0.5
*/
// add the cube to the scene
scene.add(cube);
/* RENDERING A PLANE
var geometry = new THREE.PlaneGeometry( 20, 20);
var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
var plane = new THREE.Mesh( geometry, material );
plane.rotation.set(80,0,0);
scene.add( plane );
//plane.position.x = 2;
*/
//ADDING LIGHTS
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
scene.add(spotLight);
// position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
//camera
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.minDistance = 1;
controls.maxDistance = 1000;
// when the mouse moves, call the given function
document.addEventListener('mousemove', onDocumentMouseMove, false);
//when the mouse is clicked, call the given function
document.addEventListener('click', onDocumentMouseClick, false);
}
function onDocumentMouseMove(event)
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
event.preventDefault();
// update the mouse variable
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
//TRY THIS
// intersects = raycaster.intersectObject(cube); // to get the cube only
//if the mouse hovers over the cube mesh, change its color to red
//when mouse leaves the mesh, change it back to its original color
//ONLY MAKE THESE MODIFICATION IF THE MESH IS NOT CLICKED
//BECAUSE IF IT IS CLICKED, YOU HAVE TO PAINT THE MESH ACCORDING TO THE onDocumentMouseClick()
if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === false)
{
cube.material.color.set( 0xF7F7F7 );
}
else if (isClicked === false)
{
cube.material.color.set( cube.userData.originalColor );
}
}
// 0xff0000 red
//0xF7F7F7 = gray
function onDocumentMouseClick(event) //if we detect a click event
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
event.preventDefault();
// update the mouse variable
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
//if mouse is on top of the mesh when the click occurs, change color of mesh and render GUI
if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === false)
{
isClicked = true;
cube.material.color.set( 0xff0000);
/*
var params = {
textField: "Enter value:"
}
var item = gui.add(params, "textField").onFinishChange(function (value) {
//Do something with the new value
//console.log(value);
cube.scale.y +=value;
});
*/
//when its clicked, change the visibily of the GUI
vis = gui.domElement.style.visibility;
gui.domElement.style.visibility = vis == "" ? "hidden" : "";
}
//if mouse is on top of the mesh when the click occurs, but it already marked as 'clicked', now mark it as 'unclicked'
else if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === true)
{
isClicked = false;
cube.material.color.set( cube.userData.originalColor );
//when its clicked, change the visibily of the GUI
vis = gui.domElement.style.visibility;
gui.domElement.style.visibility = vis == "" ? "hidden" : "";
// gui.__proto__.constructor.toggleHide()
//dat.GUI.toggleHide();
//gui.toggleHide()
}
}
function render()
{
// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse, camera );
renderer.render(scene, camera); //render the scene
}
function animate()
{
requestAnimationFrame( animate ); //pauses when user switches tab
controls.update();
render();
}
This problem is related to a bug in OrbitControls which was fixed with r110. Upgrading OrbitControls to r110 solves the issue.
window.onload = init();
animate(); //calling function that does all the rendering
//GLOBAL VARS
var scene, camera, renderer;
var cube;
var raycaster, mouse;
var INTERSECTED;
//global flag
var isClicked = false;
//for the camera
var controls;
//creating and rendering the GUI
params = {
yAxis: 0.00001
}
var gui = new dat.GUI();
gui.add(params, "yAxis").onFinishChange(val => {
cube.scale.y = val;
});
//we make sure to make it hidden
let vis = gui.domElement.style.visibility;
gui.domElement.style.visibility = vis == "" ? "hidden" : "";
// once everything is loaded, we run our Three.js stuff.
function init() {
// create a scene, that will hold all our elements such as objects, cameras and lights.
scene = new THREE.Scene();
//SET CAMERA
camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)
camera.position.z = 5;
// create a render and set the size
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor("#e5e5e5"); //background color
renderer.setSize(window.innerWidth,window.innerHeight); //size of renderer
//bind rendered to the dom element
document.getElementById("WebGL-output").appendChild(renderer.domElement);
//RAYCASTER
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2(1,1);
// create a cube
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xffff00 }); //0xF7F7F7 = gray
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.scale.y = 0.00001;
cube.userData.originalColor = 0xffff00;
// position the cube
cube.position.x = 0;
cube.position.y = 3;
cube.position.z = 0;
/*
//USEFUL METHODS
cube.rotation.x +=0.5
cube.scale.x +=0.5
*/
// add the cube to the scene
scene.add(cube);
/* RENDERING A PLANE
var geometry = new THREE.PlaneGeometry( 20, 20);
var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
var plane = new THREE.Mesh( geometry, material );
plane.rotation.set(80,0,0);
scene.add( plane );
//plane.position.x = 2;
*/
//ADDING LIGHTS
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
scene.add(spotLight);
// position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
//camera
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.minDistance = 1;
controls.maxDistance = 1000;
// when the mouse moves, call the given function
document.addEventListener('mousemove', onDocumentMouseMove, false);
//when the mouse is clicked, call the given function
document.addEventListener('click', onDocumentMouseClick, false);
}
function onDocumentMouseMove(event)
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
event.preventDefault();
// update the mouse variable
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
//TRY THIS
// intersects = raycaster.intersectObject(cube); // to get the cube only
//if the mouse hovers over the cube mesh, change its color to red
//when mouse leaves the mesh, change it back to its original color
//ONLY MAKE THESE MODIFICATION IF THE MESH IS NOT CLICKED
//BECAUSE IF IT IS CLICKED, YOU HAVE TO PAINT THE MESH ACCORDING TO THE onDocumentMouseClick()
if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === false)
{
cube.material.color.set( 0xF7F7F7 );
}
else if (isClicked === false)
{
cube.material.color.set( cube.userData.originalColor );
}
}
// 0xff0000 red
//0xF7F7F7 = gray
function onDocumentMouseClick(event) //if we detect a click event
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
event.preventDefault();
// update the mouse variable
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
//if mouse is on top of the mesh when the click occurs, change color of mesh and render GUI
if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === false)
{
isClicked = true;
cube.material.color.set( 0xff0000);
/*
var params = {
textField: "Enter value:"
}
var item = gui.add(params, "textField").onFinishChange(function (value) {
//Do something with the new value
//console.log(value);
cube.scale.y +=value;
});
*/
//when its clicked, change the visibily of the GUI
vis = gui.domElement.style.visibility;
gui.domElement.style.visibility = vis == "" ? "hidden" : "";
}
//if mouse is on top of the mesh when the click occurs, but it already marked as 'clicked', now mark it as 'unclicked'
else if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === true)
{
isClicked = false;
cube.material.color.set( cube.userData.originalColor );
//when its clicked, change the visibily of the GUI
vis = gui.domElement.style.visibility;
gui.domElement.style.visibility = vis == "" ? "hidden" : "";
// gui.__proto__.constructor.toggleHide()
//dat.GUI.toggleHide();
//gui.toggleHide()
}
}
function render()
{
// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse, camera );
renderer.render(scene, camera); //render the scene
}
function animate()
{
requestAnimationFrame( animate ); //pauses when user switches tab
controls.update();
render();
}
body {
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.110/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.110/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
<div id="WebGL-output">
</div>
BTW: Please always ensure to use three.js files from the same release. In your demo, three.js is from r110 whereas OrbitControls is from 101.1. Such configurations are not supported and can produce undefined behavior.
I'm using three.js for graphical website.
It's concept is universe that has many text.
If I click the text, Regardless of it's distance, object have to move to fixed position(or camera's front)
So I wrote the code like this.
[index.html]
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://gitcdn.xyz/repo/thesmart/jquery-scrollspy/0.1.3/scrollspy.js"></script>
<script src="./src/WOW.js"></script>
<script src="./src/three.js"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/ColladaLoader.js"></script>
<script src="https://unpkg.com/three.texttexture"></script>
<script src="https://unpkg.com/three.textsprite"></script>
<script src="./src/DeviceOrientationControls.js"></script>
<script src="./src/hammer.js"></script>
<script src="./src/Detector.js"></script>
<script src="./src/perlin.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" href="animate.css">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<meta charset="UTF-8">
</head>
<body>
<header>
<div class="header-left">
MAIN
</div>
<div class="header-right">
MISSION
PRODUCT
CULTURE
STORY
</div>
</header>
<main>
<!-- Universe -->
<section id="universe" class="wow" data-wow-duration="0.5s"></section>
<!-- Main -->
<section class="main" id="main">
</section>
<script src="./src/src.js"></script>
</main>
</body>
</html>
[src.js]
// VARIABLES
let clock, camera, scene, renderer, mixer;
const sleep = ms => new Promise(res => setTimeout(res, ms));
var myElement = document.getElementById("threejs");
const mouse = new THREE.Vector2();
const clicked = new THREE.Vector2();
const target = new THREE.Vector2();
const windowHalf = new THREE.Vector2( window.innerWidth / 2, window.innerHeight / 2 );
const moveState = {forward: 0, back: 0};
var isMobile = false;
var textCount = 500;
var firstTime = true;
var fontFamily = '"Courier New", Courier, monospace';
var lock = true;
var group = new THREE.Group();
const scrollPosition = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
checkMobile()
// WOW.js
var wow = new WOW();
wow.init();
init();
async function init() {
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
scene = new THREE.Scene();
// CAMERA
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2100 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 1200;
camera.lookAt(scene.position);
clock = new THREE.Clock();
// HELPER
const gridHelper = new THREE.PolarGridHelper( 8, 16 );
scene.add( gridHelper );
// LIGHT
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.2 );
scene.add( ambientLight );
const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight.position.set( 1, 1, - 1 );
scene.add( directionalLight );
// CONTROLS
if(isMobile) { // 모바일이면
var controls = new THREE.DeviceOrientationControls(camera);
console.log('isMobile true');
} else {
console.log('isMobile false');
}
// SATISFY THE DESIRES OF LOVE
let sprite = new THREE.TextSprite({
textSize: 5,
redrawInterval: 250,
texture: {
text: 'MAIN TEST',
fontFamily: fontFamily,
},
material: {
color: 'white',
},
});
sprite.position.x = 0;
sprite.position.y = 0;
sprite.position.z = 10;
scene.add(sprite);
// ADD MESH
var size = ( isMobile ? 2 : 2 );
var starsLights = new THREE.Group();
var starGeometry = new THREE.SphereGeometry(0.3, 16, 16);
var emptyGeometry = new THREE.Geometry();
for ( let i = 0; i < textCount; i ++ ) {
var lod = new THREE.LOD();
// Text
let sprite = new THREE.TextSprite({
textSize: size,
redrawInterval: 250,
texture: {
text: 'For Test',
fontFamily: fontFamily,
},
material: {
color: 'white',
transparent: true,
},
});
// Star
var starMaterial = new THREE.MeshBasicMaterial({color: 0xffffff, transparent: true});
var star = new THREE.Mesh(starGeometry, starMaterial);
// Dummy
var dummy = new THREE.Mesh(emptyGeometry, new THREE.MeshBasicMaterial());
// Add
lod.addLevel(sprite, 1);
lod.addLevel(star, 100, 240);
lod.addLevel(dummy, 200, 300);
lod.position.x = (Math.random() * 180-100);
lod.position.y = Math.random() * 180-100;
lod.position.z = Math.random() * 1000-40;
group.add(lod);
}
scene.add(group);
// Renderer
renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("universe").appendChild(renderer.domElement);
// Event handler
window.addEventListener('load', refreshCheck, false);
window.addEventListener('resize', onWindowResize, false);
document.addEventListener('mousemove', onMouseMove, false);
document.addEventListener('mousewheel', onMouseWheel, false);
document.addEventListener('contextmenu', onContextMenu, false);
document.addEventListener('mouseup', onMouseClick, false);
function animate() {
target.x = ( 1 - mouse.x ) * 0.002;
target.y = ( 1 - mouse.y ) * 0.002;
camera.rotation.x += 0.05 * ( target.y - camera.rotation.x );
camera.rotation.y += 0.05 * ( target.x - camera.rotation.y );
if(isMobile) {
controls.update();
}
// Object change related to distance
group.children.forEach(function(child) {
child.update(camera);
})
// Render
requestAnimationFrame( animate );
render(scene, camera);
}
animate();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onMouseWheel(event) {
event.preventDefault();
camera.position.z -= event.deltaY * 0.2;
}
function render() {
const delta = clock.getDelta();
if ( mixer !== undefined ) mixer.update( delta );
renderer.render( scene, camera );
}
function onTransitionEnd( event ) {
console.log("Loading Complete");
event.target.remove();
}
// Exist functions
function checkMobile() {
var UserAgent = navigator.userAgent;
if (UserAgent.match(/iPhone|iPod|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i) != null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null) {
isMobile = true;
} else {
isMobile = false;
}
}
var raycaster = new THREE.Raycaster();
var mouseVector = new THREE.Vector3();
function getIntersects( x, y ) {
x = ( x / window.innerWidth ) * 2 - 1;
y = - ( y / window.innerHeight ) * 2 + 1;
mouseVector.set( x, y, 0.5 );
raycaster.setFromCamera( mouseVector, camera );
return raycaster.intersectObject( group, true );
}
var selectedObject = null;
var intersects;
function onMouseMove(event) {
event.preventDefault();
mouse.x = ( (event.clientX/2) - (windowHalf.x/2) );
mouse.y = ( (event.clientY/2) - (windowHalf.y/2) );
clicked.x = ( event.clientX / window.innerWidth ) * 2 - 1;
clicked.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// Select object
if ( selectedObject ) {
selectedObject.material.color.set( '#ffffff' );
selectedObject = null;
}
intersects = getIntersects( event.layerX, event.layerY );
if ( intersects.length > 0 ) {
var res = intersects.filter( function ( res ) {
return res && res.object;
} )[ 0 ];
if ( res && res.object ) {
selectedObject = res.object;
selectedObject.material.color.set( '#f00' );
}
}
}
function onMouseClick() {
if(intersects[0]) {
console.log(intersects[0].point);
intersects[0].object.position.z += intersects[0].distance-70;
intersects[0].object.position.x = 0;
intersects[0].object.position.y = 0;
}
}
function onResize(event) {
const width = window.innerWidth;
const height = window.innerHeight;
windowHalf.set( width / 2, height / 2 );
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
function onContextMenu(event) { // Mouse right click
event.preventDefault();
}
function refreshCheck() {
if(window.performance) {
if(performance.navigation.type === 1) {
setTimeout(() => {
document.body.scrollTop = 0; // Other Browser
document.documentElement.scrollTop = 0; // IE
}, 0);
}
}
}
In the onMouseWheel() function, I detect current cursor point to object or not.
So, object's information will be stored in var intersects.
Also add onMouseClick(). And inside that function, I change object's position like this.
if(intersects[0]) {
console.log(intersects[0].point);
intersects[0].object.position.z += intersects[0].distance-70;
intersects[0].object.position.x = 0;
intersects[0].object.position.y = 0;
}
So if you click the object, object's x,y,z coordinate will be changed to, 0, 0, distance-70.
But it doesn't apply to the scene.
Refer to this site https://50-jahre-hitparade.ch/
If you click the text, text will be move to front of camera.
My goal is made it like above site.
(like this)
Why it doesn't work in my code?
Any solution here?
Thanks.
(Maybe I have to update into animate()?)
Source : https://github.com/teamhide/raycast
Launch : https://teamhide.github.io/raycast/
Instead of
if(intersects[0]) {
intersects[0].point.z = 100;
intersects[0].point.x = 100;
intersects[0].point.y = 100;
}
Try changing the position of the intersects[0].object.position like this,
if(intersects[0]) {
intersects[0].object.position.z = 100;
intersects[0].object.position.x = 100;
intersects[0].object.position.y = 100;
}
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! :)
I am have having issue in moving the object, when using mouse. When i move the object initially it works fine, but after rotating the scene about the y-axis, the object starts moving in opposite direction of the mouse. I have created a jsfiddle for that. Here is the code:
//define global variables here
var container, renderer;
var camera, scene, projector,mouseVector,controls;
var mouseX, mouseY, draggable;
var pen,c_mesh,interactiveObj = [];
var cube_selected=false;
var wallWidth=1200;
var wallHeight=400;
var raycaster = new THREE.Raycaster(); // create once
var mouse = new THREE.Vector2(); // create once
init();
animate();
function init(){
container=document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 10, 10000);
//camera.position.set(0,-wallWidth/2+10,wallWidth);
camera.position.set(0,-wallHeight/2+10,wallWidth);
// camera.lookAt(new THREE.Vector3(0,-wallWidth/2 +10,10));
//camera.lookAt(new THREE.Vector3(10,10,10));
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight(0x666666);
scene.add(ambient);
//walls
walls = new THREE.Object3D();
var groundMat = new THREE.MeshPhongMaterial({color:0x808080});
var groundGeo_2 = new THREE.PlaneGeometry(wallWidth, wallWidth); //for roof and floor
var ground = new THREE.Mesh(groundGeo_2, groundMat);
ground.overdraw = true;
ground.position.set(0, -wallHeight, 0);
ground.rotation.x = -Math.PI/2;
walls.add(ground);
var cube_geometry = new THREE.CubeGeometry(500,300,100);
var c_material = new THREE.MeshNormalMaterial();
c_mesh = new THREE.Mesh(cube_geometry, c_material);
c_mesh.overdraw = true;
c_mesh.name = "first_cube";
c_mesh.position.set(0, -wallHeight+100/2-1 ,0); //c_mesh.add(camera);
c_mesh.rotation.x = Math.PI * 0.1;
interactiveObj.push(c_mesh);
walls.add(c_mesh);
scene.add(walls);
//projector = new THREE.Projector();
mouseVector = new THREE.Vector3();
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
container.appendChild( renderer.domElement );
//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 );
render();
}
function render() {
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown(event){
draggable = true;
event.preventDefault();
mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( interactiveObj, true );
console.log(intersects);
if ( intersects.length > 0 ) {
if(intersects[0].object == c_mesh) {
renderer.domElement.style.cursor = 'pointer';
console.log("cube selected "); cube_selected=true;
}else{
cube_selected=false;
}
draggable = false;
}
}
function onDocumentMouseUp(event){
draggable = false;
cube_selected=false;
renderer.domElement.style.cursor = 'auto';
}
function onDocumentMouseMove( event ) {
if(draggable){
if(mouseX != 0 && mouseY != 0){
deltaX = event.clientX - mouseX;
deltaY = event.clientY - mouseY;
walls.rotation.y += deltaX * 0.01;
walls.rotation.x += deltaY * 0.01;
}
}else if (cube_selected==true){
if(mouseX != 0 && mouseY != 0){
deltaX = event.clientX - mouseX;
deltaY = event.clientY - mouseY;
c_mesh.position.x += deltaX*1.5 ;
c_mesh.position.y -= deltaY*1.5 ;
}
}
mouseX = event.clientX;
mouseY = event.clientY;
render();
}
function onDocumentMouseWheel( event ) {
mouseDelta = (-event.wheelDeltaY|| event.detail);
camera.position.z += mouseDelta * 1 ;
// console.log("camera position : "+ camera.position.z);
render();
}
https://jsfiddle.net/pn1pL4jb/5/
What i have done:
Added object in plane, rather then to scene because I want the same rotation of plane and object in the same direction.
The problem was that when you rotated the walls/ground with the mouse drag, the cube's rotation was not updated to match. So when you went to drag the cube after a world rotation, the cube is still operating in its old coordinate system. Also, be careful how you add children to parents. The cube should be a child of the scene (or world coordinate system) if you intend to move it all around. If it is a child of the floor or walls, things can get wacky really fast. :)
I updated your JSFiddle as well as cleaned up the code a little bit:
https://jsfiddle.net/aucyekux/
The magic is happening on line 126 with the copying of the wall's rotation into the cube's rotation so it matches:
c_mesh.rotation.copy(walls.rotation);
I won't assume how much 3D math you know, but I'll just say that copying the ground's rotation essentially creates a new frame of reference or local coordinate system for the cube so that when you drag it to the right, and the code says x = x + ... , its new coordinate system has its x direction pointing in the same direction as the ground/walls' new x direction (after the rotation you performed on them).
Hope this makes sense - don't worry if you don't quite get how it all works. I am a veteran 3D game programmer hobbyist for 20 years and I still sometimes forget how this all works and I have struggled with it plenty. I also refresh my understanding by browsing scratchapixel (the 3D math / coordinate system primer section) every now and then. It keeps all this 3D math stuff fresh. Good luck to you! :)
The following is a 2nd answer to this problem. The OP has added orbitControls.js to his app and now all the objects are more manageable. Here is the whole app's .html file, updated to reflect the changes. Now, you can click/drag to rotate the whole room. And then you can click/drag on the chair or the sofa and drag them around the room. Their Y positions are clamped to the ground (0.0) so that they do not incorrectly penetrate the floor.
The sliding of objects along the floor is achieved through raycasting against just the ground (when the mouse has selected them and dragging them). The raycast returns the intersection point in world space, so I just copy that into the draggable objects' position. Then a post-clamp of their Y positions prevent them from falling through the floor.
Even better, is the fact that we don't need localToWorld and worldToLocal matrix 'hacks' anymore because everything is relative to the Scene, which is how it is in real life. :) To prove this, I added an example update the chair's rotation around its own Y axis, so we have a spinning chair that is able to rotate around its own local center of gravity, while also being able to move its position relative to the Scene (world).
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head lang="en">
<meta charset="UTF-8">
<title>Room</title>
</head>
<body>
<script src="http://alexan0308.github.io/threejs/build/three.min.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 chair_rotate = false;
var walls;
var mesh_box;
var wallright, wallleft, wallback, wallfront, ceiling, ground;
var strDownloadMime = "image/octet-stream";
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);
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);
wallback = new THREE.Mesh(groundGeo, wallTextureBack);
wallback.overdraw = true;
wallback.position.set(0, wallHeight / 2, -wallWidth / 2);
walls.add(wallback);
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);
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);
});
//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(-200,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);
});
//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;
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;
} else if (intersects[0].object.name == 'sofa_model') {
container.style.cursor = 'pointer';
sofa_selected = true;
}
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);
}
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) {
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);
chair_model.position.add(intersectOffset);
}
// 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) {
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);
}
// 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>
Change line 143 of the fiddle to:
c_mesh.position.x += deltaX*1.5 * Math.cos( walls.rotation.y);
When you rotate the scene, the plane the mouse moves on doesn't rotate with it. So you have to act like it does by scaling by the cosine of the rotation.
I am trying to use Ray intersect to find out if 2 collada object collide.
But so far no success :(
my code http://jsfiddle.net/XqQzF/
object.updateMatrix();
// ray
var f_vector = new THREE.Vector3( 0, 0, -1 );
var b_vector = new THREE.Vector3( 0, 0, 1 );
var l_vector = new THREE.Vector3( -1, 0, 0 );
var r_vector = new THREE.Vector3( 1, 0, 0 );
everytime i use something its removed from the newest three.js revision.
Can you help me on the way ?
I recently update my three.js examples collection to be compatible with the latest version (v56 at time of writing), and this includes an example of collision detection. Check out http://stemkoski.github.com/Three.js/Collision-Detection.html (see http://stemkoski.github.com/Three.js/#collision-detection for instructions).
The main difference in your case will be choosing a central point of your model as an origin point for the rays, and choosing a set of vertices of your model to use as endpoints for the rays, as rays are what is used for collision detection.
Hope this helps!
#Lee Stemkoski answer is ok, when we doesn't use collada data.
First what I know is that we need min. 2 Mesh objects. So I took all Mesh objects from collada object. I wrote two scripts - first tried colliding 2 collada objects. Second tried to collide collada object with wall(simple Mesh). In both cases script it doesn't recognize colliding 😕. So how i should write it?
At last I tried to detect mouse on collada object. It's not about this topic but it's similar problem so I write it here.
Dae file was generated by SketchUp.
Code for two collada objects:
var container;
var meshs = [];
var camera, scene, renderer, raycaster;
var controls;
var mouse = new THREE.Vector2();
var dae, dae2;
var collidableMeshList = [];
var clock = new THREE.Clock();
var keyboard = new THREEx.KeyboardState();
$(document).ready(function() {
init();
animate();
});
function init() {
container = document.createElement('div');
$('.container').append(container);
camera = new THREE.PerspectiveCamera(45, 500 / 500, 1, 1000);
group = new THREE.Group();
scene = new THREE.Scene();
scene.add(camera);
camera.position.set(10 * 10, 12 * 10, 16 * 10);
camera.lookAt(scene.position);
// Lights
group.add(new THREE.AmbientLight(0x777777));
var light = new THREE.DirectionalLight(0xdfebff, 1.25);
light.position.set(300, 400, 50);
light.position.multiplyScalar(1.3);
light.castShadow = true;
group.add(light);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0xcccccc, 1);
renderer.setSize(500, 500);
container.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('./sample.dae', loadDae);
function loadDae(collada) {
dae = collada.scene;
dae.scale.x = 0.5;
dae.scale.y = 0.3;
dae.scale.z = 0.3;
dae.updateMatrix();
group.add(dae);
}
var wallGeometry = new THREE.CubeGeometry(10, 10, 20, 1, 1, 1);
var wallMaterial = new THREE.MeshBasicMaterial({
color: 0x8888ff
});
var wireMaterial = new THREE.MeshBasicMaterial({
color: 0x000000,
wireframe: true
});
loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('./sample.dae', loadDae2);
function loadDae2(collada) {
dae2 = collada.scene;
dae2.scale.x = 0.5;
dae2.scale.y = 0.3;
dae2.scale.z = 0.3;
dae2.updateMatrix();
dae2.position.set(-40, 0, 0);
dae2.traverse(function(child) {
if (child instanceof THREE.Mesh) {
collidableMeshList.push(child);
}
});
group.add(dae2);
}
group.translateX(-20);
scene.add(group);
raycaster = new THREE.Raycaster();
window.addEventListener('resize', onWindowResize, false);
window.addEventListener('mousemove', onDocumentMouseMove, false);
}
function onDocumentMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function onWindowResize() {
camera.aspect = 500 / 500;
camera.updateProjectionMatrix();
renderer.setSize(500, 500);
}
function update() {
var delta = clock.getDelta();
var moveDistance = 200 * delta;
var rotateAngle = Math.PI / 2 * delta;
if (keyboard.pressed("A"))
dae.rotation.y += rotateAngle;
if (keyboard.pressed("D"))
dae.rotation.y -= rotateAngle;
if (keyboard.pressed("left"))
dae.translateX(-moveDistance);
if (keyboard.pressed("right"))
dae.translateX(moveDistance);
if (keyboard.pressed("up"))
dae.translateZ(-moveDistance);
if (keyboard.pressed("down"))
dae.translateZ(moveDistance);
meshs = [];
if (typeof dae !== 'undefined') {
dae.traverse(function(child) {
if (child instanceof THREE.Mesh) {
meshs.push(child);
}
});
$.each(meshs, function(number_mesh, mesh) {
var originPoint = mesh.position.clone();
for (var vertexIndex = 0; vertexIndex < mesh.geometry.vertices.length; vertexIndex++) {
var localVertex = mesh.geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4(mesh.matrix);
var directionVector = globalVertex.sub(mesh.position);
var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
var collisionResults = ray.intersectObjects(collidableMeshList);
if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
console.log(" Hit ");
}
}
});
}
controls.update();
}
function animate() {
requestAnimationFrame(animate);
render();
update();
}
function render() {
renderer.render(scene, camera);
}
Code for collada + wall(Mesh):
var container;
var meshs = [];
var camera, scene, renderer, raycaster;
var controls;
var mouse = new THREE.Vector2();
var dae;
var collidableMeshList = [];
var clock = new THREE.Clock();
var keyboard = new THREEx.KeyboardState();
$(document).ready(function() {
init();
animate();
});
function init() {
container = document.createElement('div');
$('.container').append(container);
camera = new THREE.PerspectiveCamera(45, 500 / 500, 1, 1000);
group = new THREE.Group();
scene = new THREE.Scene();
scene.add(camera);
camera.position.set(10 * 10, 12 * 10, 16 * 10);
camera.lookAt(scene.position);
// Lights
group.add(new THREE.AmbientLight(0x777777));
var light = new THREE.DirectionalLight(0xdfebff, 1.25);
light.position.set(300, 400, 50);
light.position.multiplyScalar(1.3);
light.castShadow = true;
group.add(light);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0xcccccc, 1);
renderer.setSize(500, 500);
container.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('./sample.dae', loadDae);
function loadDae(collada) {
dae = collada.scene;
dae.scale.x = 0.5;
dae.scale.y = 0.3;
dae.scale.z = 0.3;
dae.updateMatrix();
group.add(dae);
}
var wallGeometry = new THREE.CubeGeometry(10, 10, 20, 1, 1, 1);
var wallMaterial = new THREE.MeshBasicMaterial({
color: 0x8888ff
});
var wireMaterial = new THREE.MeshBasicMaterial({
color: 0x000000,
wireframe: true
});
var wall = new THREE.Mesh(wallGeometry, wallMaterial);
wall.position.set(-40, 5, -10);
group.add(wall);
collidableMeshList.push(wall);
var wall = new THREE.Mesh(wallGeometry, wireMaterial);
wall.position.set(-40, 5, -10);
group.add(wall);
group.translateX(-20);
scene.add(group);
raycaster = new THREE.Raycaster();
window.addEventListener('resize', onWindowResize, false);
window.addEventListener('mousemove', onDocumentMouseMove, false);
}
function onDocumentMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function onWindowResize() {
camera.aspect = 500 / 500;
camera.updateProjectionMatrix();
renderer.setSize(500, 500);
}
function update() {
var delta = clock.getDelta();
var moveDistance = 200 * delta;
var rotateAngle = Math.PI / 2 * delta;
if (keyboard.pressed("A"))
dae.rotation.y += rotateAngle;
if (keyboard.pressed("D"))
dae.rotation.y -= rotateAngle;
if (keyboard.pressed("left"))
dae.translateX(-moveDistance);
if (keyboard.pressed("right"))
dae.translateX(moveDistance);
if (keyboard.pressed("up"))
dae.translateZ(-moveDistance);
if (keyboard.pressed("down"))
dae.translateZ(moveDistance);
meshs = [];
if (typeof dae !== 'undefined') {
dae.traverse(function(child) {
if (child instanceof THREE.Mesh) {
meshs.push(child);
}
});
$.each(meshs, function(number_mesh, mesh) {
var originPoint = mesh.position.clone();
for (var vertexIndex = 0; vertexIndex < mesh.geometry.vertices.length; vertexIndex++) {
var localVertex = mesh.geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4(mesh.matrix);
var directionVector = globalVertex.sub(mesh.position);
var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
var collisionResults = ray.intersectObjects(collidableMeshList);
if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
console.log(" Hit ");
}
}
});
}
controls.update();
}
function animate() {
requestAnimationFrame(animate);
render();
update();
}
function render() {
renderer.render(scene, camera);
}
Detect mouse on collada object. Short code version:
var meshs = [],
raycaster,
mouse = new THREE.Vector2();
...
function init() {
...
function loadDae(collada) {
dae = collada.scene;
dae.scale.x = 0.5;
dae.scale.y = 0.3;
dae.scale.z = 0.3;
dae.updateMatrix();
group.add(dae);
dae.traverse(function(child) {
if (child instanceof THREE.Mesh) {
meshs.push(child);
}
});
}
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('./sample.dae', loadDae);
raycaster = new THREE.Raycaster();
window.addEventListener('mousemove', onDocumentMouseMove, false);
...
}
...
function onDocumentMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function render() {
raycaster.setFromCamera(mouse, camera);
if (group.children.length === 5) {
var intersects = raycaster.intersectObjects(meshs);
if (intersects.length > 0) {
console.log(" Hit ");
}
}
renderer.render(scene, camera);
}
...
General - yes, it works, but throw errors with some $meshs 😕.
TypeError: undefined is not an object (evaluating 'O')
three.min.js:8304
cthree.min.js:3544
intersectObjectsthree.min.js:3609:144
Why and how to recognize which mesh is correct for intersectObjects and which not?