I want to set a different color to an object, which I selected in Three JS. I am getting the x and y position of the mouse, but the function raycaster.intersectObjects() always returns an empty array.
I am loading the data here and filling the objects array:
var objects = [];
var mousev,raycaster, scene, renderer, controls, loader;
//Load Data
loader = new THREE.ObjectLoader();
loader.load("models/selectableObjects.json", function (obj) {
scene.add(obj);
scene.traverse(function(children){
objects.push(children);
});
},
function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function (err) {
console.error('An error happened');
}
);
That's my mouse down Event listener:
raycaster = new THREE.Raycaster();
mousev = new THREE.Vector2();
document.addEventListener('mousedown', onDocumentMouseDown, false);
function onDocumentMouseDown(event){
event.preventDefault();
mousev.x = (event.clientX / renderer.domElement.width) * 2 - 1;
console.log("Mouse position X: "+mousev.x);
mousev.y = (event.clientY / renderer.domElement.height) * 2 + 1;
console.log("Mouse position Y: "+mousev.y);
raycaster.setFromCamera( mousev, camera );
var intersects = raycaster.intersectObjects( objects );
console.log("Objects: ");
console.log(objects);
console.log("Intersects: ");
console.log(intersects);
var color = (Math.random() * 0xffffff);
for ( var i = 0; i < intersects.length; i++ ) {
intersects[i].object.material.color.set( 0xff0000 );
}
}
Thank you for your help.
Related
I want to make my FBX model rotate continuously using three.js.
So I tried
make my object into variable
call my object in animate function to rotate. (girl1)
but I got an error:
Cannot read property 'rotation' of undefined.
My code is like this:
function init() {
...
// zombie girl
let loader_girl = new FBXLoader();
loader_girl.load("ZombiePunching.fbx", (object) => {
// animation mixer
mixer = new THREE.AnimationMixer(object);
const action = mixer.clipAction(object.animations[0]);
action.play();
// make materials opaque
object.traverse((child) => {
if (child.isMesh) {
child.material.transparent = false;
}
});
object.scale.set(0.05, 0.05, 0.05);
object.rotation.x = Math.PI;
scene.add(object);
girl1 = object;
});
...
let loader = new THREE.TextureLoader();
loader.load("smoke.png", function (texture) {
let cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
let cloudMaterial = new THREE.MeshLambertMaterial({
map: texture,
transparent: true,
});
for (let p = 0; p < 25; p++) {
let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
cloud.position.set(
Math.random() * 800 - 400,
500,
Math.random() * 500 - 450
);
cloud.rotation.x = 1.16;
cloud.rotation.y = -0.12;
cloud.rotation.z = Math.random() * 360;
cloud.material.opacity = 0.6;
cloudParticles.push(cloud);
scene.add(cloud);
}
});
}
function animate() {
cloudParticles.forEach((p) => {
p.rotation.z -= 0.002;
});
rainGeo.vertices.forEach((p) => {
p.velocity -= 0.1 + Math.random() * 0.1;
p.y += p.velocity;
if (p.y < -200) {
p.y = 200;
p.velocity = 0;
}
});
rainGeo.verticesNeedUpdate = true;
rain.rotation.y += 0.002;
girl1.rotation.y += 0.001;
if (Math.random() > 0.93 || flash.power > 100) {
if (flash.power < 100)
flash.position.set(Math.random() * 400, 300 + Math.random() * 200, 100);
flash.power = 50 + Math.random() * 500;
}
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
init();
animate();
Instead of doing this:
girl1.rotation.y += 0.001;
try it with:
if ( girl1 ) girl1.rotation.y += 0.001;
Since you start the animation loop before the FBX is actually loaded, girl1 will be undefined for a certain amount of time.
so this is the first time i try to learn how to create web with 3 js and tween js. i created multiple object when user click 1 of object it will display its content. but when i try to move the camera to face the object (zooming and focus on the selected the object), the camera just jump to the top of canvas and scan all of the canvas.
(function() {
var DZOOM, OX, OY, aspectt, camera, height, light, loader, render, renderer, scene, view, width, raycaster, intersects, INTERSECTED;
var objects = [],
uuids = [],
names = [];
var container = document.getElementById( 'main-content' );
var windowHalfX = container.offsetWidth / 2;
var windowHalfY = container.offsetHeight / 2;
width = container.offsetWidth;
height = container.offsetHeight;
var raycaster = new THREE.Raycaster();
var lookAtVector = new THREE.Vector3(0,0,0);
var mouse = new THREE.Vector2(),
INTERSECTED;
document.body.appendChild( container );
aspectt = width / height;
scene = new THREE.Scene();
scene.background = new THREE.Color( '#fff' );
camera = new THREE.PerspectiveCamera(85, window.innerWidth / window.innerHeight, 1, 1000);
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
windowHalfX = container.offsetWidth / 2;
windowHalfY = container.offsetHeight / 2;
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize( container.offsetWidth, container.offsetHeight );
}
renderer.setSize(width, height);
container.appendChild( renderer.domElement );
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(15, -5, 15);
scene.add(light);
OX = -35;
OY = -5;
if (!deviceIsMobile()) {
camera.position.set(OX + 60, OY - 5, 35);
}
else{
camera.position.set(OX + 30, OY - 10, 20);
}
camera.up = new THREE.Vector3(0, 0, 1);
camera.lookAt(new THREE.Vector3(OX, OY, 0));
container.addEventListener( 'mousedown', onDocumentMouseDown, false );
container.addEventListener( 'touchstart', onDocumentTouchStart, false );
container.addEventListener( 'touchmove', onDocumentTouchMove, false );
function displayCaptionOnClick( event ) {
event.preventDefault();
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObjects( objects[0].children, true );
if ( intersects.length > 0 ) {
for( var i = 0; i < intersects.length; i++ ) {
displayCaption(intersects[0].object.uuid);
}
}
}
function redOnHover( event ) {
event.preventDefault();
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObjects( objects[0].children, true );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
INTERSECTED.material.emissive.setHex( 0xff0000 );
}
} else {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
}
}
function toObj(obj) {
console.log(obj);
var normalMatrix = new THREE.Matrix3().getNormalMatrix( obj.matrixWorld );
var worldNormal = new THREE.Vector3(0,0,1).applyMatrix3( normalMatrix ).normalize();
console.log(worldNormal);
var camPosition = new THREE.Vector3().copy(obj.position).add(worldNormal.multiplyScalar(100));
var rotateTween = new TWEEN.Tween(lookAtVector)
.to({
x: obj.position.x,
y: obj.position.y,
z: obj.position.z
}, 4000)
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(function(){
camera.lookAt(lookAtVector);
})
.onComplete(function(){
lookAtVector.copy(obj.position);
})
.start();
var goTween = new TWEEN.Tween(camera.position)
.to(camPosition, 4000)
.easing(TWEEN.Easing.Quadratic.InOut)
.start();
}
function displayCaption( uuid ) {
var curObj = uuids.indexOf(uuid);
console.log(curObj);
if(curObj<=7){
$('.single-page').hide();
var crnt= $('#'+curObj);
crnt.show();
$('#sidebar').animate({right:0});
redOnHover( event );
}
}
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
function animate() {
requestAnimationFrame(animate);
render();
}
render = function() {
TWEEN.update();
camera.updateMatrixWorld();
return renderer.render(scene, camera);
};
function onDocumentMouseDown( event ) {
event.preventDefault();
container.addEventListener( 'mousemove', onDocumentMouseMove, false );
container.addEventListener( 'mouseup', onDocumentMouseUp, false );
container.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
checkClick(event);
displayCaptionOnClick( event );
toObj(INTERSECTED);
}
var myObj;
loader = new THREE.ObjectLoader();
loader.load("js/try.dae.json",function ( obj ) {
if (!deviceIsMobile()) {
obj.scale.x = obj.scale.y = obj.scale.z = 2.3;
}
else{
obj.scale.x = obj.scale.y = obj.scale.z = 0.8;
}
// FIXED
obj.position.x = -15;
obj.position.y = -5;
obj.position.z = 24;
obj.rotation.y = 0.15;
obj.rotation.z = 0.6;
myObj = obj;
scene.add( obj );
objects.push(obj);
console.log(objects);
var exclude = ["Cylinder_007", "Cube_005", "Cube_004", "Cylinder_006", "Cylinder_005", "Cylinder_004", "Cylinder_003", "Cylinder_002", "Plane_004", "Plane_003", "Plane_002", "Cube_003", "Cube_002", "Cube", "Cube_001", "Cylinder_001", "Plane_001", "Cylinder", "Torus_001", "Text"];
for( var i = 0; i < objects[0].children.length; i++ ) {
if ( exclude.indexOf(objects[0].children[i].name) < 0 ) {
uuids.push(objects[0].children[i].children[0].uuid);
}
}
for( var i = 0; i < objects[0].children.length; i++ ) {
uuids.push(objects[0].children[i].children[0].uuid);
}
return render();
});
animate();
}).call(this);
I want to make a animated tube with hemisphere ends, the tubular segments is 200. I have the vertices from the first 60 segments to copy the position of a SphereGeometry's upper half part, and the last 60 segments lower half part.
The segments between the upper and lower hemisphere is all copied to the vertices around the sphere's equatorial.
The geometry looks fine, but the spherical environment mapping texture is discontinued at the sphere's equatorial.
I have my code as below, anyone know how to solve the problem?
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 28, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 50;
scene = new THREE.Scene();
var nMat = new THREE.MeshNormalMaterial({side:THREE.DoubleSide,});
var tube = new DSTube( 200, 30, 10, nMat);
scene.add( tube.mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0px;
background-color: #000000;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r78/three.js"></script>
<script>
function DSTube( lengthSeg, radiusSeg, radius, material ) {
//for speed
this.framerate = 60;
//center
this.origin = new THREE.Vector3();
this.head = this.origin;
this.tail = this.origin;
//setup
this.lengthSeg = lengthSeg;
this.radiusSeg = radiusSeg;
this.radius = radius;
this.pathPoints = [];
for(var i=0; i<this.lengthSeg; i++) {
this.pathPoints.push( new THREE.Vector3( 0, 0, 0) );
}
// TubeGeometry(path, tubularSegments, radius, radiusSegments, closed)
this.geometry = new THREE.TubeGeometry( new THREE.CatmullRomCurve3(this.pathPoints), this.lengthSeg, this.radius, this.radiusSeg, false );
this.material = material;
this.mesh = new THREE.Mesh( this.geometry, this.material );
this.verticeCount = this.geometry.vertices.length;
//sphere part
//adjust height segment if needed
this.sphereHeightSegments = 60;
//SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
this.headSphere = new THREE.SphereGeometry( this.radius, this.radiusSeg, this.sphereHeightSegments );
this.tailSphere = new THREE.SphereGeometry( this.radius, this.radiusSeg, this.sphereHeightSegments );
this.sphereVerticeCount = this.headSphere.vertices.length;
//count for tube hemisphere
this.headHemisphereVerticeCount = ( this.sphereHeightSegments / 2 + 1 ) * this.radiusSeg;
//layer
this.tubeLayerCount = this.lengthSeg + 1;
this.headHemisphereLayerCount = this.tailHemisphereLayerCount = this.sphereHeightSegments / 2 + 1;
this.tailHemisphereStartLayer = this.tubeLayerCount - this.sphereHeightSegments / 2;
this.middleLayerCount = this.tubeLayerCount - this.headHemisphereLayerCount * 2;
this.initGeometry();
// return this.mesh;
}
DSTube.prototype.initGeometry = function() {
this.copyHeadSphere();
this.copyInitialTubePart();
this.copyTailSphere();
}
DSTube.prototype.copyHeadSphere = function() {
//copy head hemisphere vertice
for( var y = 0; y < this.headHemisphereLayerCount; y++ ) {
for( var x = 0; x < this.radiusSeg; x++ ) {
if( x == 0 ) {
var sphereVertex = this.headSphere.vertices[ y * (this.radiusSeg + 1) + x ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
} else {
var sphereVertex = this.headSphere.vertices[ y * (this.radiusSeg + 1) + ( this.radiusSeg - x ) ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
}
}
}
this.geometry.computeBoundingSphere();
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
DSTube.prototype.copyInitialTubePart = function() {
//copy head hemisphere vertice
for( var y = this.headHemisphereLayerCount - 1; y < this.tubeLayerCount ; y++ ) {
for( var x = 0; x < this.radiusSeg; x++ ) {
var vertex = this.geometry.vertices[ ( this.headHemisphereLayerCount - 1 ) * this.radiusSeg + x ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( vertex );
}
}
this.geometry.computeBoundingSphere();
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
DSTube.prototype.copyTailSphere = function() {
//copy tail hemisphere vertice
for( var y = this.tailHemisphereStartLayer; y < this.tubeLayerCount; y++ ) {
for( var x = 0; x < this.radiusSeg; x++ ) {
if( x == 0 ) {
var sphereVertex = this.tailSphere.vertices[ ( y - this.middleLayerCount - 1 ) * (this.radiusSeg + 1) + x ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
} else {
var sphereVertex = this.tailSphere.vertices[ ( y - this.middleLayerCount - 1 ) * (this.radiusSeg + 1) + ( this.radiusSeg - x ) ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
}
}
}
this.geometry.computeBoundingSphere();
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
</script>
I would like to setup a mouse move event handler for my three.js but was unable to relate it to mouse and make it successful it could be really helpful if some one could say how can i do it. I know no were i am using mouse related coordinates but i am worried to do something affects my calculation part.
root = document.getElementById("WebGL");
window.addEventListener('resize', onWindowResize(width, height), false);
root.addEventListener('mousemove', MouseMoveGoogleMapsUpdate(), false);
function MouseMoveGoogleMapsUpdate(){
var angle = onMouseMove();
line.setMap(null); //removing the old lines on circle
var newstartpoint = pointGoogleMaps(circle.getRadius() * Math.cos(-angle[0]),
circle.getRadius() * Math.sin(-angle[0]), origin);
var viewdir = pointGoogleMaps(circle.getRadius() * Math.cos(-angle[1]),
circle.getRadius() * Math.sin(-angle[1]), origin);
var newendpoint = pointGoogleMaps(circle.getRadius() * Math.cos(angle[2]),
circle.getRadius() * Math.sin(angle[2]), origin);
line = new google.maps.Polyline({
path: [newstartpoint, origin, newendpoint],
geodesic: true, //By setting it to true the distance is cal in meters
strokeColor: '#0000FF',
strokeOpacity: 0.8,
strokeWeight: 2,
map: map
});
}
function onMouseMove(){
var degrees = Math.PI/180.0;
var raycaster = new THREE.Raycaster();
var viewingDir = camera.getWorldDirection();
var Vectors = [0,0,0];
var Angles = [0,0,0];
for(i=0; i<3; i++)
{
Vectors[i] = new THREE.Vector3(i-1, 0, 0.5);
raycaster.setFromCamera(Vectors[i], camera);
Vectors[i].sub(camera.position);
Vectors[i].normalize();
}
for(i=0; i<3; i+=2)
{
var dotp = Vectors[i].x * Vectors[1].x + Vectors[i].y * Vectors[1].y + Vectors[i].z * Vectors[1].z;
if (dotp >= 1)
Angles[i] = 0.0;
else if (dotp <= -1)
Angles[i] = Math.PI;
else
Angles[i] = Math.acos(dotp);
}
Angles[1] = Math.atan2(viewingDir.x, -viewingDir.z);
fov = Angles[0] + Angles[2];
Angles[0] = Angles[1] - 0.5 * fov; //x-dir
Angles[2] = Angles[1] + 0.5 * fov; //y-dir
return Angles;
}
canvas.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;
}
I don't see event in your code ...
When I drag the mouse left or right, i'd like drag the scene, don't rotate camera.
I tried
camera.position.x = mouseX;
camera.position.y = mouseY;
but scene rotated
I tried change position in scene — scene rotated.
How to drag the scene?
You can try using (after you define your camera)
controls = new THREE.RollControls(camera);
controls.movementSpeed = 10;
controls.lookSpeed = 1;
controls.rollSpeed = 0;
controls.autoForward = false;
after including this in your html:
<script type="text/javascript" src="three.js/examples/js/controls/RollControls.js"></script>
In addition you would have to change your onWindowResize event to add
controls.handleResize();
and your render() function to add
controls.update(clock.getDelta());
and your init() function to add
clock = new THREE.Clock();
here is a file i got at github that might work
THREE.DragControls = function(_camera, _objects, _domElement) {
if (_objects instanceof THREE.Scene) {
_objects = _objects.children;
}
var _projector = new THREE.Projector();
var _mouse = new THREE.Vector3(),
_offset = new THREE.Vector3();
var _selected;
_domElement.addEventListener('mousemove', onDocumentMouseMove, false);
_domElement.addEventListener('mousedown', onDocumentMouseDown, false);
_domElement.addEventListener('mouseup', onDocumentMouseUp, false);
function onDocumentMouseMove(event) {
event.preventDefault();
_mouse.x = (event.clientX / _domElement.width) * 2 - 1;
_mouse.y = -(event.clientY / _domElement.height) * 2 + 1;
var ray = _projector.pickingRay(_mouse, _camera);
if (_selected) {
var targetPos = ray.direction.clone().multiplyScalar(_selected.distance).addSelf(ray.origin);
_selected.object.position.copy(targetPos.subSelf(_offset));
return;
}
var intersects = ray.intersectObjects(_objects);
if (intersects.length > 0) {
_domElement.style.cursor = 'pointer';
} else {
_domElement.style.cursor = 'auto';
}
}
function onDocumentMouseDown(event) {
event.preventDefault();
_mouse.x = (event.clientX / _domElement.width) * 2 - 1;
_mouse.y = -(event.clientY / _domElement.height) * 2 + 1;
var ray = _projector.pickingRay(_mouse, _camera);
var intersects = ray.intersectObjects(_objects);
if (intersects.length > 0) {
_selected = intersects[0];
_offset.copy(_selected.point).subSelf(_selected.object.position);
_domElement.style.cursor = 'move';
}
}
function onDocumentMouseUp(event) {
event.preventDefault();
if (_selected) {
_selected = null;
}
_domElement.style.cursor = 'auto';
}
}