I am having the following function to get the selected object, so my function is here
function onMouseDown(event) {
console.log(event);
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// find intersections
var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
projector.unprojectVector( vector, camera );
var pLocal = new THREE.Vector3(0, 0, -1);
var pWorld = pLocal.applyMatrix4(camera.matrixWorld);
var ray = new THREE.Raycaster(pWorld, vector.sub(pWorld).normalize());
ray.set( camera.position, vector.sub( camera.position ).normalize() );
var intersects = ray.intersectObjects( scene.children );
//console.log(intersects);
console.log(scene.children);
if ( intersects.length > 0 ) {
var clickedObject = intersects[0].object;
console.log('objects '+intersects[ 0 ].object);
console.log('objects id'+intersects[ 0 ].object.id);
console.log('objects name'+intersects[ 0 ].object.name);
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
console.log('INTERSECTED '+INTERSECTED);
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
INTERSECTED.material.emissive.setHex( 0xff0000 );
}
} else {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
}
}
but am getting empty array on intersects , i tried my level best but i can't find any solution here, if i console the scene.children i can see all the attached objects of the scene
on before this am adding the object into scene as like here
var loader = new THREE.JSONLoader();
loader.load("uploads/accessories/3d/code/3dfile_"+file+".js",
function(geometry, object_material)
{
var object = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(object_material));
model = new THREE.Object3D();
model.id="Myid"+file;
model.name="Myname"+file;
model.userData ={ URL: "http://myurl.com" };
model.add(object);
model.position.set(x,y,z);
model.scale.set(obj_width,obj_height,obj_rotation);
model.opacity =2;
model.rotation.y = 600;
model.duration = 12000;
model.mirroredLoop = true;
model.castShadow = true;
model.receiveShadow = true;
console.log(model);
var smodel=model;
scene.add(smodel);
}
);
now i want to get the added model by new THREE.Object3D(); in onMouseDown but i can't, any one have the same issue ?
You need to pass in the recursive flag to Raycaster.intersectObjects().
intersects = ray.intersectObjects( scene.children, true );
Also, do not overwrite Object3D.id. Set Object3D.userData.id instead.
three.js r.68
You are using a MeshFaceMaterial which doesn't have a hex to grab. You have to get the 'materials array' from the 'material' like so:
for(var p =0; p < INTERSECTED.material.materials.length; p++){
INTERSECTED.currentHex = INTERSECTED.material.materials[p].emissive.getHex();
}
This way you are not selecting the MeshFaceMaterial but the MeshLambertMaterial or MeshBasicMaterial that you are using for each face. If you are using images as your textures I would suggest checking out Three.js material texture and color for a quick answer to that question.
Hope this was helpful!
Raycaster is little bit tricky I have added explanation
A typical setup need to be done for raycaster to work as follows:
first initialize a variable to hold mouse position from which we need to emit a ray
var mouse = {
x: 0,
y: 0
};
//object intersected
var INTERSECTED;
// pool of objects which can be selected
var objects = [];
// ray caster initialization
var raycaster = new THREE.Raycaster();
We need to create a Object3D parent to hold all child meshes
let mainGroup = new THREE.Object3D();
// add into object pool
objects.push(mainGroup);
scene.add(mainGroup);
// add mesh to be select by ray caster in Object3D parent
mainGroup.add(meshToSelect);
Add an event listener to get mouse X,Y position
document.addEventListener("mousemove", this.onDocumentMouseMove, false);
onDocumentMouseMove = event => {
event.preventDefault();
if (event && typeof event !== undefined) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
};
Now use raycaster like this:
renderScene = () => {
// Emit ray
raycaster.setFromCamera(mouse, this.camera);
// all intersects
var intersects = raycaster.intersectObjects(objects, true);
if (intersects.length > 0) {
if (INTERSECTED != intersects[0].object) {
//if new item selected swap color of new item
//& revert color of previous item
if (INTERSECTED)
INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
INTERSECTED = intersects[0].object;
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
INTERSECTED.material.color.setHex(0xff0000);
}
} else {
// None selected then revert color of previous item
if (INTERSECTED)
INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
INTERSECTED = null;
}
if (this.renderer) this.renderer.render(scene, this.camera);
};
Try to make through this example. Look at messages in the console.
<script src="js/controls/EventsControls.js"></script>
EventsControls = new EventsControls( camera, renderer.domElement );
EventsControls.draggable = false;
EventsControls.onclick = function() {
console.log( this.focused.name );
}
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load( "models/Tux.js", addModelToScene );
function addModelToScene( geometry, materials ) {
var material = new THREE.MeshFaceMaterial( materials );
model = new THREE.Mesh( geometry, material );
model.scale.set( 10, 10, 10 ); model.name = 'Tux';
model.rotation.x = -Math.PI/2;
model.position.set( 175, 45, 125 );
scene.add( model );
EventsControls.attach( model );
}
Related
I'm new to THREE.js.
For the purpose of learning JavaScript and THREE.js I made this (kind of) Mini Game where player is able to explore space and different space objects (work in process).
Anyways, my problem is when the scene and objects are rendered, and you start moving your cuboid, camera doesn't move with it (actually it doesn't move away from the world origin) only rotates in place looking at the player's object.
This is the code:
import './style.css'
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// Scene object
const scene = new THREE.Scene();
const clock = new THREE.Clock();
var cameraObject, keys;
var temp = new THREE.Vector3;
var dir = new THREE.Vector3;
var a = new THREE.Vector3;
var b = new THREE.Vector3;
var distance = 0.3;
var velocity = 0.0;
var speed = 0.0;
// Camera object
const perspectiveCamera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 50, 1e7 )
perspectiveCamera.position.setZ(80);
cameraObject = new THREE.Object3D;
cameraObject.add(perspectiveCamera);
// perspectiveCamera.lookAt(scene.position)
// Renderer object
const renderer = new THREE.WebGLRenderer({
});
document.body.appendChild( renderer.domElement );
// Renderer
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.render( scene, perspectiveCamera )
// Light
// PointLight
const pointLight = new THREE.PointLight(0xffffff)
pointLight.position.set(20,20,20)
// AmbientLight
const ambientLight = new THREE.AmbientLight(0xffffff)
scene.add(pointLight, ambientLight)
// Helper classes
const lightHelper = new THREE.PointLightHelper(pointLight);
const axesHelper = new THREE.AxesHelper(5);
scene.add(lightHelper, axesHelper)
// Controls
const controls = new OrbitControls(perspectiveCamera, renderer.domElement);
controls.movementSpeed = 1000;
controls.domElement = renderer.domElement;
controls.rollSpeed = Math.PI / 24;
controls.autoForward = false;
controls.dragToLook = false;
let cube = new THREE.Group();
const cubeGeometry = new THREE.BoxGeometry(3,10,3)
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x238423 })
const cube1 = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.add(cube1)
scene.add(cube)
// Objects
// Stars
function addStar() {
const geometry = new THREE.SphereGeometry(0.25, 24, 24);
const material = new THREE.MeshStandardMaterial( { color: 0xffffff })
const star = new THREE.Mesh( geometry, material );
const [x, y, z] = Array(3).fill().map(() => THREE.MathUtils.randFloatSpread( 500 ));
star.position.set(x,y,z);
scene.add(star)
}
Array(1500).fill().forEach(addStar)
let keyState = {};
keys = {
a: false,
s: false,
d: false,
w: false,
q: false,
e: false,
space: false,
shiftleft: false,
};
document.addEventListener("keydown", function(e) {
console.log(e.code);
const key = e.code.replace('Key', '').toLowerCase();
if ( keys[ key ] !== undefined )
keys[ key ] = true;
});
document.body.addEventListener( 'keyup', function(e) {
const key = e.code.replace('Key', '').toLowerCase();
if ( keys[ key ] !== undefined )
keys[ key ] = false;
});
// Animate objects
function animate() {
const delta = clock.getDelta();
requestAnimationFrame( animate );
speed = 0.0;
if ( keys.w )
cube.rotateX(-0.03);
if ( keys.s )
cube.rotateX(0.03);
if ( keys.a )
cube.rotateZ(0.03);
if ( keys.d )
cube.rotateZ(-0.03);
if ( keys.q )
cube.rotateY(-0.06);
if ( keys.e )
cube.rotateY(0.06);
if ( keys.space )
speed = 0.9;
velocity += ( speed - velocity ) * .3;
cube.translateY( velocity );
if ( keys.shiftleft )
speed = 0.9*5;
velocity += ( speed - velocity ) * .3;
cube.translateY( velocity );
perspectiveCamera.lookAt( cube.position );
controls.update(delta);
renderer.render( scene, perspectiveCamera );
}
animate();
I'm actually trying to make some sort of Third Person Camera. In order to make the camera follow this little cuboid and rotate as the object rotates on the screen.
First attempt:
const idealOffset = new THREE.Vector3(0, 0, -80);
function animate(){
...
perspectiveCamera.position.set(0, 0, -80);
perspectiveCamera.applyQuaternion(cube.rotation);
perspectiveCamera.position.add(cube.position);
perspectiveCamera.lookAt(idealOffset);
...
}
Camera moves with the cube but after a few seconds turns back to look at the world origin.
Second attempt:
// Animate objects
requestAnimationFrame( function animate(milliseconds) {
const delta = clock.getDelta();
let moveDistance = 10*delta;
let rotateAngle = Math.PI/2*delta;
requestAnimationFrame( animate );
speed = 0.0;
if ( keys.w ){
cube.rotateX(-0.03);
}
if ( keys.s ){
cube.rotateX(0.03);
}
let rotation_matrix = new THREE.Matrix4().identity();
if ( keys.a ){
cube.rotateZ(rotateAngle);
}
if ( keys.d ){
cube.rotateZ(-rotateAngle);
}
if ( keys.q ){
cube.rotateY(-rotateAngle);
}
if ( keys.e ){
cube.rotateY(rotateAngle);
}
if ( keys.space ){
speed = 0.9;
velocity += ( speed - velocity ) * .3;
cube.translateY( velocity );
}
if ( keys.shiftleft ){
speed = 0.9*5;
velocity += ( speed - velocity ) * .3;
cube.translateY( velocity );
}
var relativeCameraOffset = new THREE.Vector3(0,-80,0);
var cameraOffset = relativeCameraOffset.applyMatrix4(cube.matrixWorld);
perspectiveCamera.position.x = cameraOffset.x;
perspectiveCamera.position.y = cameraOffset.y;
perspectiveCamera.position.z = cameraOffset.z;
perspectiveCamera.lookAt(cube.position);
renderer.render( scene, perspectiveCamera );
});
Camera does follow my cube but when I rotate it 180 DEG on x-axis it turns upside-down,it's fixed to the player and doesn't move smoothly and it looks directly at the player (back side of the cube).
This inspired me to read more about rotating/translating in 3d space, about Euler angles, quaternions, gimbal lock. I'm just not quite sure how to apply these scary quaternions to my project...
Any help, reference, whatever would be greatly appreciated.
Thanks in advance.
If you're using OrbitControls, just update the .target property to the position of the object you want it to focus on. When the cube moves, the camera will move with it. See here for more on the docs:
orbitControls.target = cube.position;
I'm not sure why you're doing this: cameraObject.add(perspectiveCamera);. This doesn't do anything if you don't make any changes to cameraObject.
I have loaded a 3D terrain via Blender with the OBJLoader. I have also created a mesh (yellow pointer on the picture below) which i want to follow the mouse while it's on the terrain.
I tried to use the raycaster method but i don't know exactly how to apply it to my .obj as it seems that I can't access it outside the loader.
How can i make my pointer(yellow mesh) stick to my terrain (loaded .obj) while it's following the mouse ?
Please help a total three.js noob...
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 10000 );
var renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera.position.z = 150;
camera.position.y=300;
camera.position.x=350;
var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
scene.add( light );
var controls= new THREE.OrbitControls(camera,renderer.domElement);
controls.enableDamping=true;
controls.campingFactor=0.25;
controls.enableZoom=true;
controls.minDistance= 1;
controls.maxDistance=3000;
controls.minPolarAngle= -Math.PI/2;
controls.maxPolarAngle= Math.PI/2;
var terrain;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load('models/terrain.mtl',
(materials) => {
materials.preload();
var loader = new THREE.OBJLoader();
loader.setMaterials(materials);
loader.load(
'models/terrain.obj',
function ( object ) {
terrain = object;
scene.add( terrain );
});
}
);
var Cylindergeometry = new THREE.CylinderGeometry( 5, 0, 8, 32 );
var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var cylinder = new THREE.Mesh( Cylindergeometry, material );
var Torusgeometry = new THREE.TorusGeometry( 7, 0.5, 8, 6);
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var torus = new THREE.Mesh( Torusgeometry, material);
Torusgeometry.rotateX(1.5708);
Torusgeometry.translate(0,-4.5,0);
//Merge the two parts to make it one mesh (yellow pivot)
var PivotGeometry = new THREE.Geometry();
PivotGeometry.merge(Cylindergeometry);
PivotGeometry.merge(Torusgeometry);
var pivot = new THREE.Mesh(PivotGeometry, material);
scene.add(pivot);
// Trying to Raycast the terrain to make the pivot follow the mouse while it's on it
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onMouseMove( event ) {
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
// See if the ray from the camera into the world hits one of our meshes
var intersects = raycaster.intersectObject( terrain,true );
// Toggle rotation bool for meshes that we clicked
if ( intersects.length > 0 ) {
pivot.position.set( 0, 0, 0 );
pivot.lookAt( intersects[ 0 ].face.normal );
pivot.position.copy( intersects[ 0 ].point );
}
}
//Met à jour l'affichage de la scène
var animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
My loaded .obj terrain
You have the following line in your code:
var intersects = raycaster.intersectObjects( object );
I don't see where object as a variable is declared. I suggest you declare this variable in your module scope, assign the loaded OBJ file to it and then use this code instead:
var intersects = raycaster.intersectObject( object, true );
OBJLoader.load() returns an object of type THREE.Group which is in some sense a container holding an arbitrary number of meshes. Hence, you want to raycast recursively.
I have been trying to add a raycaster to my game for some time now. After testing a lot of situations, I have found that the raycaster IS functioning.
There is a scene that contains various enemy objects, and a floor. Same scene. A raycaster is supposed to be sending a ray out from the cursor to things on this scene. However, only the floor is detected as a collision, while all of the other objects cannot be detected.
This is currently being hosted here: http://aceverything.com/cskelly/project2/
Here are some relevant fragments:
function render() {
//console.log(object.position);
// LATER: IMPLEMENT NICER GUN ANIMATION
global_m60.position.x += ( mouseX - global_m60.position.x ) * .45;
if(-mouseY < 1){
global_m60.position.y += ( - mouseY - global_m60.position.y ) * .45;
}
else{
global_m60.position.y = 1;
}
for(i = 0; i < enemy_tanks.length ; ++i){
enemy_tanks[i].position.z += .01;
}
projector.unprojectVector( mouse, camera );
mouse.sub( camera.position );
mouse.normalize();
var raycaster = new THREE.Raycaster( camera.position, mouse );
var intersects = raycaster.intersectObjects( scene.children );
for( var i = 0; i < intersects.length; ++i ){
intersects[i].object.material.map = THREE.ImageUtils.loadTexture("models/red_checkerboard.jpg");
intersects[i].object.material.needsUpdate = true;
console.log("RAY STUFF HAPPENING");
}
camera.lookAt( scene.position );
renderer.clear();
renderer.render( scene, camera );
renderer.clearDepth();
renderer.render( sandbag_scene, camera );
renderer.clearDepth();
renderer.render( scene2, camera );
framecount += 1;
}
Me loading in the objects that are NOT being detected:
// ENEMIES
mtlLoader.setPath('models/');
for(i = 0; i < max_tanks; ++i){
mtlLoader.load( 'ultimate-tank.mtl', function( materials2 ) {
//materials2.needsUpdate = true;
materials2.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials2 );
//objLoader.setPath( 'obj/male02/' );
objLoader.load( 'models/ultimate-tank.obj', function ( object2 ) {
object2.position.x = (Math.random()*30)-15;
object2.position.y = -1;
object2.position.z = 220;
//object2.position.y = -95;
global_enemy_1 = object2;
global_enemy_1.rotateY(1.507);
//global_enemy_1.renderOrder = 1;
enemy_tanks.push(global_enemy_1);
scene.add( global_enemy_1 ); // THIS HAS TO BE DONE LIKE THIS.
//global_enemy_1.material.color.set( 0xff0000 ); THIS DOESNT WORK...
}, onProgress, onError );
});
}
The original intention was to change the material of objects the raycaster comes into contact with to visually show me that there was a collision. The material part is irrelevant. The part that matters is that:
var intersects = raycaster.intersectObjects( scene.children );
clearly isn't giving me the objects. What gives?
I understand there is no THREE.projector in version 71 (see the deprecated list), but I don't understand how to replace it, particularly in this code that detects which object has been clicked on:
var vector = new THREE.Vector3(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1,
0.5
);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(
camera.position,
vector.sub(camera.position).normalize()
);
var intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0) {
clicked = intersects[0];
console.log("my clicked object:", clicked);
}
There is now an easier pattern that works with both orthographic and perspective camera types:
var raycaster = new THREE.Raycaster(); // create once
var mouse = new THREE.Vector2(); // create once
...
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( objects, recursiveFlag );
three.js r.84
The THREE.JS raycaster documentation actually gives all the relevant information that is laid out in these answers as well as all the missing points that may be difficult to get your head around.
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onMouseMove( event ) {
// calculate mouse position in normalized device coordinates
// (-1 to +1) for both components
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function render() {
// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse, camera );
// calculate objects intersecting the picking ray var intersects =
raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
intersects[ i ].object.material.color.set( 0xff0000 );
}
renderer.render( scene, camera );
}
window.addEventListener( 'mousemove', onMouseMove, false );
window.requestAnimationFrame(render);`
Hope it helps.
You can use the latest recommended version as stated above.
To get your specific code working, replace:
projector.unprojectVector( vector, camera );
with
vector.unproject(camera);
I noted that all this that was said before is fine in a full window I think, but if you have other things besides a canvas on the page you need to get the click events target's offset and remove it.
e = event and mVec is a THREE.Vector2
let et = e.target, de = renderer.domElement;
let trueX = (e.pageX - et.offsetLeft);
let trueY = (e.pageY - et.offsetTop);
mVec.x = (((trueX / de.width) * 2) - 1);
mVec.y = (((trueY / de.height) * -2) + 1);
wup.raycaster.setFromCamera( mVec, camera );
[Then check for intersections, etc.]
Looks like you need to watch for dragging (mouse movements) too or releasing from a drag will trigger an unwanted click when using window.addEventListener( 'click', function(e) {<code>});
[You'll notice I put the negative sign where it's more logical as well.]
https://github.com/mrdoob/three.js/issues/5587
var vector = new THREE.Vector3();
var raycaster = new THREE.Raycaster();
var dir = new THREE.Vector3();
...
if ( camera instanceof THREE.OrthographicCamera ) {
vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, - 1 ); // z = - 1 important!
vector.unproject( camera );
dir.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
raycaster.set( vector, dir );
} else if ( camera instanceof THREE.PerspectiveCamera ) {
vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); // z = 0.5 important!
vector.unproject( camera );
raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
}
var intersects = raycaster.intersectObjects( objects, recursiveFlag );
Objects = array of objects of type Object3D to check for intersection with the ray. Can be everything in your scene, but might be inefficient if you have a lot of stuff there.
recursiveFlag = If true, it also checks all descendants. Otherwise it only checks intersection with the object. Default is true.
docs
I wanted to share my experiences with more details doing this since I feel the answers above do not really explain the details to get this going.
In my case I was using STL_Viewer, you can locate it here (https://www.viewstl.com/plugin/), it helps create a threeJS scene and supplies you with the camera and scene that you will need for this to work.
function mouse_click_normalize(clientX,clientY,offset_left,offset_top){
var mouse = new THREE.Vector2(); // create once
var c = document.getElementById("stl_contEye").childNodes[0];//get canvas element created in here
mouse.x = ( (event.clientX-offset_left) / (c.clientWidth) * 2) - 1;
mouse.y = - ( (event.clientY-offset_top) / (c.clientHeight) ) * 2 + 1;
console.log(`clientX=${clientX},clientY=${clientY},mouse.x=${mouse.x},mouse.y=${mouse.y}\nwidth=${c.clientWidth},height=${c.clientHeight},offset_left=${offset_left},offset_top=${offset_top}`);
return mouse;
}
Above is my function that will automatically normalize the x,y coordinates in the space that was clicked (between -1 and 1), as this is what the raycaster requires for it's setFromCamera function.
Because you may be clicking in a section of the screen with offsets I programmed it this way so it will handle no matter how it's positioned in the DOM. Just replace "stl_contEye" with the name of your div that will contain the rendered ThreeJS or STLViewer in my case.
function model_clicked(model_id, e, distance, click_type){
console.log(e);
var pos = new THREE.Vector3(); // create once and reuse
// var vec = new THREE.Vector3(); // create once and reuse
var camera = stl_viewer1.camera;
var scene = stl_viewer1.scene;
// vec.unproject( camera );
// vec.sub( camera.position ).normalize();
// //var distance2 = (distance - camera.position.z) / vec.z;
// pos.copy( camera.position ).add( vec.multiplyScalar( distance ) );
var mouse_coords_normalized = mouse_click_normalize(e.clientX,e.clientY,e.srcElement.offsetLeft,e.srcElement.offsetTop);
var raycaster = new THREE.Raycaster(); // create once
raycaster.setFromCamera( mouse_coords_normalized, camera );
//console.log(raycaster);
//console.log(scene);
var intersects = raycaster.intersectObjects( scene.children, true );
if(intersects.length > 0){
console.log(intersects);
console.log(intersects[0].point);
pos = intersects[0].point
}
}
By doing it this way, you will get the exact point in 3D space from where you clicked. The function model_clicked simply returns an event that holds the clientX or clientY, you just have to get this yourself somehow if you are not using STLViewers event for detecting a click. There are many examples above for this from the other answers.
I hope this helps someone trying to figure this out with or without stl_viewer
camera.shooting = Date.now()
document.getElementById("div5").addEventListener("mousedown", mousedown);
document.getElementById("div5").addEventListener("mouseup", mouseup);
document.getElementById("div5").addEventListener( 'mousemove', renderq);
function mousedown(event) {
camera.calculator = 1;
}
function mouseup(event) {
camera.calculator = 0;
}
function renderq(event){
if( ai2bcz.length > 0 && ai_key3.length > 0 ){
if( camera.calculator > 0 ){
camera.mouse = new THREE.Vector2();
var fleece = document.getElementById("div5").scrollHeight;
var fleeceb = document.getElementById("div5").scrollWidth;
var fees = (event.clientX / fleeceb) - 1;
var feesa = - (event.clientY / fleece) + 1;
camera.mouse.x = fees ; camera.mouse.y = feesa;
var sphereMaterialc = new THREE.MeshBasicMaterial({color: 0x0099FF});
var sphereGeoc = new THREE.SphereGeometry(5, 5, 5);
var spherec = new THREE.Mesh(sphereGeoc, sphereMaterialc);
spherec.position.set(camera.position.x, camera.position.y, camera.position.z);
spherec.raycaster = new THREE.Raycaster();
spherec.raycaster.setFromCamera( camera.mouse, camera);
spherec.owner = 'player';
spherec.health = 100;
bulletsc.push(spherec);
scene.add(spherec);
camera.lastshot = Date.now();
camera.shooting = Date.now();
}
}
}
function render() { const controlscamera = new FirstPersonControls(camera);
controlscamera.update(100);
if( ai2bcz.length > 0 && ai_key3.length > 0 ){
if( camera.calculator > 0 && camera.shooting + 25 < Date.now() ){
renderq(event)
camera.shooting = Date.now();
}}
if(bulletsc.length > 1){
for (var i = 0; i < bulletsc.length - 1; i++) {
var bu = bulletsc[i], pu = bu.position, du = bu.raycaster.ray.direction;
if(bu.owner == "player"){
var enemybulletspeeda = window.document.getElementById("bulletsplayerspeed").value;
bu.translateX(enemybulletspeeda * du.x);
bu.translateY(enemybulletspeeda * du.y);
bu.translateZ(enemybulletspeeda * du.z);
}
}}
renderer.render( scene, camera ); }
I'm trying to reset the position of my latest Object in three.js.
First of all I have this:
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
projector.unprojectVector( vector, camera );
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) {
controls.enabled = false;
SELECTED = intersects[ 0 ].object;
container.style.cursor = 'move';
//mouse Click goes here
buildMenu();
}
}
In my buildMenu Function I position my Object like this:
function buildMenu(){
camera.position.set(0,60,250);
//HERE I POSITION MY SELECTED OBJECT
SELECTED.position.x = 0;
SELECTED.position.y = 50;
SELECTED.position.z = 200;
$(document).bind('click',function(){
$(document).click(function(){
scene.remove(overlayBG);
**//HERE I TRY TO RESET EVERYTHING BUT NOTHING WORKS : (**
});
});
//$('#bg, #menu').fadeIn(100)
}
I thought I can easily reset my Object by mesh.position.set(0,0,0) inside the $(document).click Function but that doesn't work. How can I detect the latest (Re-Positioned) Object and how can I reposition it.
I'm not sure if I understood correctly.
Made a simple example, You don't need to bind any click events for this. Example is here
//last selected object
if ( SELECTED ){
SELECTED.position.set(0,0,0);
}
//new selected object
SELECTED = intersects[ 0 ].object;