ThreeJs Badly sees the coordination of the mouse through the canvas - three.js

Structure of my project 66% threejs model, 44% html (side control) using Bootstrap.
Iā€™m trying to make mouse picker, when pointing at an object so that it is shown on which object it is pointed. As I understand it, he sees the coordination of the mouse badly.
Please help me figure out and set up the correct coordination mouse with Canvas.
Project Structure Screenshot:
Code:
export class CustomizerComponent implements OnInit {
public textureSrc: string;
public textureList = [
{ id: 1, name: 'Wood 2', src: '/assets/textures/wood2.jpg' },
{ id: 2, name: 'Wood 1', src: '/assets/textures/wood1.jpg' },
];
public selectedTexture(e): void {
let find = this.textureList.find((x) => x?.src === e.target.value);
// console.log(find?.src);
}
ngOnInit(): void {
let scene, kitchen, camera, renderer, canvas, controls, mouse, raycaster, loader, BACKGROUND_COLOR = 0xffffff;
// Scene
scene = new THREE.Scene();
scene.background = new THREE.Color(BACKGROUND_COLOR);
// Renderer with canvas
canvas = document.getElementById('canvas');
renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.setSize(canvas.width * 3.5, canvas.height * 5);
console.log(canvas.clientWidth);
renderer.shadowMap.enabled = true;
// Set Camera
camera = new THREE.PerspectiveCamera(
75,
canvas.clientWidth / canvas.clientHeight,
0.1,
1000
);
camera.position.z = 5;
camera.position.x = 5;
camera.position.y = 1;
mouse = new THREE.Vector2();
raycaster = new THREE.Raycaster();
// Controls with options
controls = new OrbitControls(camera, renderer.domElement);
controls.maxPolarAngle = Math.PI / 2;
controls.minPolarAngle = Math.PI / 3;
controls.enableDamping = true;
controls.enablePan = false;
controls.target.set(5, 1, 0);
controls.maxAzimuthAngle = 0.8;
controls.minAzimuthAngle = -0.8;
controls.enableZoom = false;
controls.dampingFactor = 0.1;
controls.autoRotate = false;
controls.autoRotateSpeed = 0.2; // 30
loader = new GLTFLoader();
loader.load(
'assets/3d_models/kitch.glb',
(gltf) => {
kitchen = gltf.scene;
scene.add(kitchen);
console.log(kitchen);
},
undefined,
(err) => {
console.log(err);
}
);
function hoverPieces() {
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
// console.log(intersects);
for (let i = 0; i < intersects.length; i++) {
intersects[i].object.material = material;
}
console.log(intersects);
}
// Set Lights
setLights(scene);
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
hoverPieces();
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
}
animate();
function onMouseMove(event) {
// calculate pointer position in normalized device coordinates
// (-1 to +1) for both components
mouse.x = ((event.clientX - 250) / canvas.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / canvas.clientHeight) * 2 + 1;
}
window.addEventListener('mousemove', onMouseMove);
}
}
function setLights(scene) {
// Add lights
var hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.61);
hemiLight.name = 'hemiLight';
hemiLight.position.set(0, 50, 0);
// Add hemisphere light to scene
scene.add(hemiLight);
var dirLight = new THREE.DirectionalLight(0xffffff, 0.54);
dirLight.name = 'dirLight';
dirLight.position.set(-8, 12, 8);
// dirLight.castShadow = true;
dirLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
// Add directional Light to scene
scene.add(dirLight);
var light = new THREE.DirectionalLight(0xffffff, 3);
light.name = 'light';
light.position.set(10, 10, 10);
scene.add(light);
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
var width = canvas.clientWidth;
var height = canvas.clientHeight;
var canvasPixelWidth = canvas.clientWidth / window.devicePixelRatio;
var canvasPixelHeight = canvas.clientHeight / window.devicePixelRatio;
const needResize = canvasPixelWidth !== width || canvasPixelHeight !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
Gist link :
https://gist.github.com/artur33s/e15abda28707231863ded08ccfe0887d

I suggest you use pointermove instead of mousemove and also use getBoundingClientRect() in your event listener:
function onPointerMove(event) {
const rect = renderer.domElement.getBoundingClientRect();
mouse.x = ( ( event.clientX - rect.left ) / ( rect.right - rect.left ) ) * 2 - 1;
mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
}
window.addEventListener('pointermove', onPointerMove);

Related

Make the plane draggable in ThreeJS

How to make the plane draggable in X , Y direction. Here I'm trying to work on box clipping where I draw a plane on X and Y direction. But I have no idea how to make it draggable to the particular direction. Can anyone help me put with the issue.
I want to make the plane to be draggable only in the own direction on mouse event
import * as THREE from '../build/three.module.js';
import Stats from './jsm/libs/stats.module.js';
import { GUI } from './jsm/libs/dat.gui.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { DragControls } from './jsm/controls/DragControls.js';
var camera, scene, renderer, startTime, object, stats;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 0.0001, 100000);
camera.position.set(0, 1.3, 8);
scene = new THREE.Scene();
// Lights
scene.add(new THREE.AmbientLight(0x505050));
scene.background = new THREE.Color('white')
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.angle = Math.PI / 5;
spotLight.penumbra = 0.2;
spotLight.position.set(2, 3, 3);
spotLight.castShadow = true;
spotLight.shadow.camera.near = 3;
spotLight.shadow.camera.far = 10;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
scene.add(spotLight);
var dirLight = new THREE.DirectionalLight(0x55505a, 1);
dirLight.position.set(0, 3, 0);
dirLight.castShadow = true;
dirLight.shadow.camera.near = 1;
dirLight.shadow.camera.far = 10;
dirLight.shadow.camera.right = 1;
dirLight.shadow.camera.left = - 1;
dirLight.shadow.camera.top = 1;
dirLight.shadow.camera.bottom = - 1;
dirLight.shadow.mapSize.width = 1024;
dirLight.shadow.mapSize.height = 1024;
scene.add(dirLight);
// ***** Clipping planes: *****
var localPlane = new THREE.Plane(new THREE.Vector3(0, - 1, 0), 1.5);
var helper1 = new THREE.PlaneHelper(localPlane, 3, 0xffff00);
scene.add(helper1);
var globalPlane = new THREE.Plane(new THREE.Vector3(- 1, 0, 0), 1);
var helper = new THREE.PlaneHelper(globalPlane, 3, 0xffff00);
scene.add(helper); // Geometry
var material = new THREE.MeshPhongMaterial({
color: 0x80ee10,
shininess: 100,
side: THREE.DoubleSide,
// ***** Clipping setup (material): *****
clippingPlanes: [localPlane],
clipShadows: true
});
var geometry = new THREE.TorusKnotBufferGeometry(0.4, 0.08, 95, 20);
object = new THREE.Mesh(geometry, material);
object.castShadow = true;
scene.add(object);
var ground = new THREE.Mesh(
new THREE.PlaneBufferGeometry(9, 9, 1, 1),
new THREE.MeshPhongMaterial({ color: 0xa0adaf, shininess: 150 })
);
ground.rotation.x = - Math.PI / 2; // rotates X/Y to X/Z
ground.receiveShadow = true;
// scene.add( ground );
// Stats
stats = new Stats();
document.body.appendChild(stats.dom);
// Renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
window.addEventListener('resize', onWindowResize, false);
document.body.appendChild(renderer.domElement);
// ***** Clipping setup (renderer): *****
var globalPlanes = [globalPlane],
Empty = Object.freeze([]);
renderer.clippingPlanes = Empty; // GUI sets it to globalPlanes
renderer.localClippingEnabled = true;
renderer.clippingPlanes = globalPlanes;
// Controls
var controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 1, 0);
controls.update();
// controls1 = new DragControls([...globalPlane], camera, renderer.domElement);
// controls1.addEventListener('drag', render);
// GUI
var gui = new GUI(),
folderLocal = gui.addFolder('Local Clipping'),
propsLocal = {
get 'Enabled'() {
return renderer.localClippingEnabled;
},
set 'Enabled'(v) {
renderer.localClippingEnabled = v;
},
get 'Shadows'() {
return material.clipShadows;
},
set 'Shadows'(v) {
material.clipShadows = v;
},
get 'Plane'() {
return localPlane.constant;
},
set 'Plane'(v) {
localPlane.constant = v;
}
},
folderGlobal = gui.addFolder('Global Clipping'),
propsGlobal = {
get 'Enabled'() {
console.log('hitting 1')
return renderer.clippingPlanes !== Empty;
console.log(renderer.clippingPlanes);
},
set 'Enabled'(v) {
console.log('hitting 2')
renderer.clippingPlanes = v ? globalPlanes : Empty;
console.log(renderer.clippingPlanes);
},
get 'Plane'() {
return globalPlane.constant;
},
set 'Plane'(v) {
globalPlane.constant = v;
}
};
folderLocal.add(propsLocal, 'Enabled');
folderLocal.add(propsLocal, 'Shadows');
folderLocal.add(propsLocal, 'Plane', 0.3, 1.25);
folderGlobal.add(propsGlobal, 'Enabled');
folderGlobal.add(propsGlobal, 'Plane', - 0.4, 3);
// Start
startTime = Date.now();
document.addEventListener('click', onClick, false);
}
function onClick(event) {
event.preventDefault();
if (enableSelection === true) {
var draggableObjects = controls.getObjects();
draggableObjects.length = 0;
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersections = raycaster.intersectObjects(objects, true);
if (intersections.length > 0) {
var object = intersections[0].object;
if (group.children.includes(object) === true) {
object.material.emissive.set(0x000000);
scene.attach(object);
} else {
object.material.emissive.set(0xaaaaaa);
group.attach(object);
}
controls.transformGroup = true;
draggableObjects.push(group);
}
if (group.children.length === 0) {
controls.transformGroup = false;
draggableObjects.push(...objects);
}
}
render();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
// var currentTime = Date.now();
// var time = ( currentTime - startTime ) / 1000;
requestAnimationFrame(animate);
// object.position.y = 0.8;
// object.rotation.x = time * 0.5;
// object.rotation.y = time * 0.2;
// object.scale.setScalar( Math.cos( time ) * 0.125 + 0.875 );
stats.begin();
renderer.render(scene, camera);
stats.end();
}
In order to move things in three.js you use TransformControls. Check out https://threejs.org/docs/#examples/en/controls/TransformControls for its documentation and https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_transform.html for implementation example.
Here you can set the mode to "translate" and scale to "XY" to restrict the movement in X and Y direction only.
controls.axis ="XY";

MTLLoader breaks other 3js code and isn't loading texture right

I am having trouble getting the MTLLoader to work correctly. I have already been able to use the OBJLoader by itself to load the 3d object and I have a camera that works properly too in my scene. When I try and use the MTLLoader with the OBJLoader the object loads but it breaks my other three.js code. I get these errors:
three.js:24415 Uncaught TypeError: Cannot set property 'value' of undefined
at initMaterial (three.js:24415)
at setProgram (three.js:24493)
at WebGLRenderer.renderBufferDirect (three.js:23552)
at renderObject (three.js:24269)
at renderObjects (three.js:24239)
at WebGLRenderer.render (three.js:24037)
at render (demo2.html:480)
The object loads and it looks like some textures load but the textures don't look right, the camera breaks. I have been having trouble with this and could really use some guidance.
Here is my MTLLoader code by itself
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
Here is the rest of my three.js code for reference
<script>
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const renderer2 = new THREE.WebGLRenderer({canvas});
var kitchenCameraActive = false;
document.getElementById("roomSelect").addEventListener("change", changeIt);
function changeIt(e) {
document.getElementById(e.target.value).click();
console.log(e);
}
var fov = 45;
var aspect = 2; // the canvas default
var near = 0.1;
var far = 100;
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-97.570, 5.878, -5.289);
camera.rotation.set(0,0,0);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
document.getElementById("kitchen").addEventListener("click", changeCamera);
document.getElementById("bathroom").addEventListener("click", changeCamera);
document.getElementById("deck").addEventListener("click", changeCamera);
document.getElementById("livingRoom").addEventListener("click", changeCamera);
document.getElementById("bedRoom").addEventListener("click", changeCamera);
document.getElementById("walkway").addEventListener("click", changeCamera);
document.getElementById("sideHouse").addEventListener("click", changeCamera);
document.getElementById("frontPorch").addEventListener("click", changeCamera);
document.getElementById("garageDoor").addEventListener("click", changeCamera);
document.getElementById("insideGarage").addEventListener("click", changeCamera);
function changeCamera(e) {
camera.rotation.set(e.toElement.attributes[5].nodeValue,
e.toElement.attributes[6].nodeValue, e.toElement.attributes[7].nodeValue);
camera.fov = e.toElement.attributes[4].nodeValue;
camera.position.set(e.toElement.attributes[1].nodeValue,
e.toElement.attributes[2].nodeValue, e.toElement.attributes[3].nodeValue);
camera.updateProjectionMatrix();
if (e.target.id == "walkway" || e.target.id == "frontPorch" || e.target.id ==
"garageDoor" || e.target.id == "insideGarage")
{
controls.target.set(0, 5, 0);
controls.update();
}
if(e.target.id == "kitchen"){
controls.target.set(7, 6, 7);
}
if(e.target.id == "bathroom"){
controls.target.set(-9,15,-7);
}
if(e.target.id == "deck"){
controls.target.set(31, 7, 1);
}
if(e.target.id == "livingRoom"){
controls.target.set(-12.5, 1.5, -18.5);
}
if(e.target.id == "bedRoom"){
controls.target.set(-15.7, 14, -21);
}
if(e.target.id == "insideGarage"){
controls.target.set(24.405, 6.733, -6.425);
}
controls.update();
console.log(e);
}
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
}
{
const skyColor = 0xB1E1FF; // light blue
const groundColor = 0xB97A20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(5, 10, 2);
scene.add(light);
scene.add(light.target);
}
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
} );
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function onPositionChange(o) {
console.log("position changed in object");
console.log(o);
console.log('camera_default: '+camera.position.x+', '+camera.position.y+',
'+camera.position.z);
console.log('camera_default: '+camera.rotation.x+', '+camera.rotation.y+',
'+camera.rotation.z);
console.log(camera.fov);
console.log('quaternion_default: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
}
controls.addEventListener('change', onPositionChange);
var mouse = new THREE.Vector2();
var raycaster, mouse = { x : 0, y : 0};
init();
function init () {
//Usual setup code here.
raycaster = new THREE.Raycaster();
renderer.domElement.addEventListener( 'click', raycast, false );
}
function raycast ( e ) {
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//var mouse3D = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, -(
event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
//raycaster.setFromCamera( mouse3D, camera );
//3. compute intersections
var intersects = raycaster.intersectObjects( scene.children, true );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ].object.name );
}
}
}
main();
</script>

Object moving in different direction after rotating the plane, three js(v73)

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.

THREE.JS Update 64 - SpriteMaterial - definition changed

I have a current application that runs on Three.js V60. I want to migrate it to V64 but I have issue with one of functionnality which is a mouse tooltip. It follows the example from http://stemkoski.github.io/Three.js/Mouse-Tooltip.html.
In V64, we don't have useScreenCoordinates, sizeAttenuation and alignment properties, so i have strange behaviour with the tooltip when I removed this parameters. The behaviour I have is that mousetooltip is fixed on scene. Can someone help me ?
Below is a testing code I have made :
<pre><code>
// standard global variables
var container, scene, camera, renderer, controls, stats;
// custom global variables
var cube;
var projector, mouse = { x: 0, y: 0 }, INTERSECTED;
var ballSprite;
init();
animate();
// FUNCTIONS
function init()
{
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
// RENDERER
renderer = new THREE.WebGLRenderer( {antialias:true} );
renderer.setClearColor(0xFFFFFF, 1.0);
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
// LIGHT
var light = new THREE.PointLight(0xffffff);
light.position.set(0,250,0);
scene.add(light);
////////////
// CUSTOM //
////////////
var cubeGeometry = new THREE.CubeGeometry( 50, 50, 50 );
var cubeMaterial = new THREE.MeshBasicMaterial( { color: 0x000088 } );
cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.position.set(0,26,0);
scene.add(cube);
// initialize object to perform world/screen calculations
projector = new THREE.Projector();
// when the mouse moves, call the given function
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
var ballTexture = THREE.ImageUtils.loadTexture( 'http://stemkoski.github.io/Three.js/images/redball.png' );
var ballMaterial = new THREE.SpriteMaterial( { map: ballTexture} );
ballSprite = new THREE.Sprite( new THREE.SpriteMaterial(ballMaterial) );
ballSprite.scale.set( 32, 32, 1.0 );
ballSprite.position.set( 50, 50, 0 );
scene.add( ballSprite );
}
function onDocumentMouseMove( event )
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
// event.preventDefault();
// update sprite position
ballSprite.position.set( event.clientX, event.clientY, 0 );
}
function animate()
{
requestAnimationFrame( animate );
render();
update();
}
function update()
{
}
function render()
{
renderer.clear();
renderer.render( scene, camera );
}
</code></pre>
Update :
I have looked at the webgl_sprites.html example and have adapted my using ortho cam. It works partially : I have now the tooltip that is display orthogonally but it doesn't follow the mouse (while it works with previous V60).
While the example uses a picture, I use a canvas2D to draw some text and lines, convert it as a texture and apply it to a spriteMaterial and create a mesh from it.
When I drag the mouse, the mesh coordonates changed but on the screen, it stays static.
Can someone helps me?
Here is the code :
<pre><code>
THREE.MouseTooltip = function (o) {
Object.call(this);
var defaults = { // default options
ResourcesPath: "", // Location of ressoruce file
ImagesPath: "",
Scene: null,
Container: null
};
this.options = $.extend(defaults, o); // merge defaults and options object
if (this.options.Scene == null || this.options.Container == null) {
throw "Error : MouseTooltip scene and container inputs must be specified";
return;
}
this.canvas = null;
this.context = null;
this.texture = null;
this.material = null;
this.mesh = null;
this.width = 0
this.updateDisplay = false;
this.init(this.options.Scene);
};
THREE.MouseTooltip.prototype = Object.create(Object.prototype);
THREE.MouseTooltip.prototype.init = function (scene) {
this.canvas = document.createElement('canvas');
this.canvas.width = this.options.Container.offsetWidth;
this.canvas.height = this.options.Container.offsetHeight;
this.context = this.canvas.getContext('2d');
this.context.font = "20px Arial";
this.context.fillStyle = "rgba(0,0,0,0.95)";
this.context.fillText('', 0, 20);
this.width = 20;
this.texture = new THREE.Texture(this.canvas);
this.texture.needsUpdate = true;
this.material = new THREE.SpriteMaterial({ map: this.texture/*, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.topLeft */});
this.mesh = new THREE.Sprite(this.material);
this.mesh.name = "tooltip";
this.mesh.scale.set(this.canvas.width/1.5, this.canvas.height/1.5, 1.0);
this.mesh.material.depthTest = false;
this.mesh.material.transparent = false;
this.mesh.matrixAutoUpdate = false;
this.mesh.visible = false;
this.mesh.userData = "";
scene.add(this.mesh);
};
THREE.MouseTooltip.prototype.setContent = function (message) {
if (message == this.mesh.userData) {
return;
}
var metrics = this.context.measureText(message);
var lineHeight = 20;
this.width = metrics.width + 8;
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.fillStyle = "rgba(0,0,0,1)"; // black border
this.context.beginPath();
this.context.moveTo(0, (lineHeight + 8) / 2);
this.context.lineTo(10, (lineHeight + 8) / 2 + 10);
this.context.lineTo(10, (lineHeight + 8) / 2 - 10);
this.context.lineTo(0, (lineHeight + 8) / 2);
this.context.fill();
this.context.closePath();
this.context.fillRect(12, 0, this.width, lineHeight + 8);
this.context.fillStyle = "rgba(255,255,255,1)"; // white filler
this.context.fillRect(14, 2, this.width - 4, lineHeight + 4);
this.context.fillStyle = "rgba(0,0,0,1)"; // text color
this.context.fillText(message, 16, lineHeight);
this.mesh.userData = message;
this.texture.needsUpdate = true;
};
THREE.MouseTooltip.prototype.isVisible = function (b) {
return this.mesh.visible;
};
THREE.MouseTooltip.prototype.hide = function (b) {
this.mesh.visible = false;
};
THREE.MouseTooltip.prototype.show = function (b) {
this.mesh.visible = true;
};
THREE.MouseTooltip.prototype.clear = function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.texture.needsUpdate = true;
};
THREE.MouseTooltip.prototype.move = function (mouseX, mouseY) {
this.mesh.position.x = (mouseX - this.options.Container.offsetLeft+16) - this.canvas.width;
this.mesh.position.y = (mouseY - this.options.Container.offsetTop) - this.canvas.height;
this.mesh.position.z = 1;
};
</pre></code>
Regarding to the example in http://threejs.org/examples/webgl_sprites.html your actual positions would be
this.mesh.position.x = -(SCREEN_WIDTH / 2) + mouseX;
this.mesh.poyition.y = (SCREEN_WIDTH / 2) - mouseY;

two collada object colliding

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?

Resources