Conditional Drag Drop using DragControl in three.js - javascript

I want to activate/deactivate the DragControls depending on the value of a flag drag_flag, but my approach doesn't work well!
can you please tell me how can I do that properly? thanks in advance.
var drag_flag = true;
function change_drag_flag(){
drag_flag = !drag_flag;
}
var objects = [];
var scene = new THREE.Scene();
let box_geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshPhongMaterial();
const box = new THREE.Mesh(box_geometry, material);
objects.push(box);
scene.add(box);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(5, 5, 5);
scene.add(spotLight);
spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-5, 5, 5);
scene.add(spotLight);
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0.1, 4, 1);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var drag_controls = new THREE.DragControls(objects, camera, renderer.domElement);
if(drag_flag===true){
drag_controls.activate();
drag_controls.enabled = true;
}
else{
drag_controls.deactivate();
drag_controls.enabled = false;
}
renderer.render(scene, camera);
<button type="button" onclick="change_drag_flag()">Change Drag Flag</button>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/DragControls.js"></script>

You are rendering your scene only once so you don't see the effect of enabling/disabling the controls. I've slightly rewritten your code to make things work:
const objects = [];
const scene = new THREE.Scene();
const box_geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshPhongMaterial();
const box = new THREE.Mesh(box_geometry, material);
objects.push(box);
scene.add(box);
const spotLight1 = new THREE.SpotLight(0xffffff);
spotLight1.position.set(5, 5, 5);
scene.add(spotLight1);
const spotLight2 = new THREE.SpotLight(0xffffff);
spotLight2.position.set(-5, 5, 5);
scene.add(spotLight2);
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0.1, 4, 1);
camera.lookAt(scene.position);
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const dragControls = new THREE.DragControls(objects, camera, renderer.domElement);
function toggleDrag() {
dragControls.enabled = !dragControls.enabled;
}
function animate() {
requestAnimationFrame(animate);
if (dragControls.enabled === true) {
dragControls.activate();
} else {
dragControls.deactivate();
}
renderer.render(scene, camera);
}
animate();
body {
margin: 0;
}
<button type="button" onclick="toggleDrag()" style="position:absolute">Change Drag Flag</button>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/DragControls.js"></script>

Related

ThreeJs different Text on each face of cube

I'm working on Threejs to animate a cube with different text on each cube faces. I used DynamicTexture to place text on cube faces, but it places same text on each side of cube. I don't know how to place different text on each side. Is there any way to do is and place text on runtime by user inputs? Thanks.
Main.js
var scene = new THREE.Scene();
scene.background = new THREE.Color('white');
var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(4, 4, 4);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('display').appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera);
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText('Text', undefined, 256, 'green');
var geometry = new THREE.BoxGeometry(2, 2, 2);
var material = new THREE.MeshBasicMaterial({color: 0xffffff, map: dynamictexture.texture, opacity:1,
transparent: true});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
function animate() {
requestAnimationFrame(animate);
controls.update();
dynamictexture.texture
renderer.render(scene, camera);
};
animate();
You can use THREE.MeshFaceMaterial(materials) to accomplish this. All you need to do is pass an array containing the materials and specifying the map for each of the faces.
var face_textures = [];
function createFaceTextures() {
var i;
for(i = 0; i < 6; i++) {
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText(i.toString(), undefined, 256, 'green');
face_textures.push(dynamictexture);
}
}
createFaceTextures();
var scene = new THREE.Scene();
scene.background = new THREE.Color('white');
var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(4, 4, 4);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('display').appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera);
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText('Text', undefined, 256, 'green');
var geometry = new THREE.BoxGeometry(2, 2, 2,);
var material = new THREE.MeshBasicMaterial({color: 0xffffff, map: dynamictexture.texture, opacity:1, transparent: true});
var materials = [
new THREE.MeshBasicMaterial({map: face_textures[0].texture}),
new THREE.MeshBasicMaterial({map: face_textures[1].texture}),
new THREE.MeshBasicMaterial({map: face_textures[2].texture}),
new THREE.MeshBasicMaterial({map: face_textures[3].texture}),
new THREE.MeshBasicMaterial({map: face_textures[4].texture}),
new THREE.MeshBasicMaterial({map: face_textures[5].texture})
];
var cube = new THREE.Mesh(geometry, materials);
scene.add(cube);
function animate() {
requestAnimationFrame(animate);
controls.update();
dynamictexture.texture
renderer.render(scene, camera);
}
animate();

Why does "light.castShadow = true" cause my scene to break?

I am trying to build a simple solar system with sun, earth and moon, using threejs. The system includes lighting and shadows.
My only problem is, while creating the shadow that will be cast from earth to the moon and vice-versa, my script will stop working.
Console gives me an error of "isMultiSample is not defined".
I have tried searching the web but could not find any solutions to why the error would occur.
The part causing problems:
var sunLight = new THREE.PointLight(0x404040, 10, 1000000);
sunLight.position.set(0, 0, 0);
sunLight.castShadow = true; // This line will cause the error
Full code:
<script>
var camera, scene, renderer;
var spaceBox, sunPivot, earthPivot, moonPivot;;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 4000000 );
camera.position.z = 2400;
scene = new THREE.Scene();
// Surrounding space
var texture = new THREE.TextureLoader().load( 'space.jpg' );
var skygeometry = new THREE.BoxBufferGeometry( 15000, 15000, 15000 );
var skymaterial = new THREE.MeshBasicMaterial({ map: texture, side : THREE.DoubleSide});
spaceBox = new THREE.Mesh(skygeometry, skymaterial);
scene.add(spaceBox);
// Sun, earth and moon textures
var sunTexture = new THREE.TextureLoader().load('sun.jpg')
var sunGeometry = new THREE.SphereBufferGeometry(800, 32, 32);
var sunMaterial = new THREE.MeshPhongMaterial({ map: sunTexture });
var earthTexture = new THREE.TextureLoader().load('earth.jpg')
var earthGeometry = new THREE.SphereBufferGeometry(250, 32, 32);
var earthMaterial = new THREE.MeshPhongMaterial({ map: earthTexture, side: THREE.DoubleSide });
var moonTexture = new THREE.TextureLoader().load('moon.jpg')
var moonGeometry = new THREE.SphereBufferGeometry(80, 32, 32);
var moonMaterial = new THREE.MeshPhongMaterial({ map: moonTexture, side: THREE.DoubleSide });
// LIGHTS
var ambientLight = new THREE.AmbientLight(0x404040,3); // soft white light
scene.add(ambientLight);
var sunLight = new THREE.PointLight(0x404040, 10, 1000000);
sunLight.position.set(0, 0, 0);
//sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 1024;
sunLight.shadow.mapSize.height = 1024;
sunLight.shadow.camera.near = 500;
sunLight.shadow.camera.far = 10000;
sunLight.shadow.camera.fov = 30;
scene.add(sunLight);
// Add sun, earth and moon rotating around eachother
sun = new THREE.Mesh(sunGeometry, sunMaterial);
scene.add(sun);
earthPivot = new THREE.Object3D();
sun.add(earthPivot);
earth = new THREE.Mesh(earthGeometry, earthMaterial);
earth.position.x = 4000;
earth.castShadow = true;
earth.receiveShadow = true;
earthPivot.add(earth);
moonPivot = new THREE.Object3D();
earth.add(moonPivot);
var moon = new THREE.Mesh(moonGeometry, moonMaterial);
moon.position.x = 750;
moon.castShadow = true;
moon.receiveShadow = true;
moonPivot.add(moon);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
//
controls = new THREE.OrbitControls(camera, 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() {
earthPivot.rotation.y += 0.002;
moonPivot.rotation.y += 0.005;
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}</script>

threejs: Move camera to position inside another object

I'm trying to move the camera controlled by trackballControl into the position of an object.
Right now it's working but as you can see in my fiddle, each time the camera changes position it also changes the z which isn't what I want.
I'm trying to keep the same position but only rotate the globe into the position of the cube.
Here is my code so far
var camera, scene, renderer, controls, cubeMesh;
document.querySelector('button').onclick = function () {
camera.position.copy(cubeMesh.position);
camera.lookAt(controls.target);
};
var initLights = function () {
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);
var light = new THREE.DirectionalLight(0x002288);
light.position.set(-1, -1, -1);
scene.add(light);
var light = new THREE.AmbientLight(0x222222);
scene.add(light);
};
var init = function () {
renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 300;
scene = new THREE.Scene();
controls = new THREE.TrackballControls(camera);
controls.target.set(0, 0, 0);
controls.rotateSpeed = 2;
document.body.appendChild(renderer.domElement);
var sphereGeom = new THREE.SphereGeometry(100, 32, 32);
var sphereMat = new THREE.MeshPhongMaterial({
color: 0xfb3550,
flatShading: true
});
var sphereMesh = new THREE.Mesh(sphereGeom, sphereMat);
//cube
var cubeDim = 20;
var cubeGeom = new THREE.BoxGeometry(cubeDim, cubeDim, cubeDim);
var cubeMat = new THREE.MeshPhongMaterial({
color: 0x7cf93e,
flatShading: true
});
cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
var spherical = new THREE.Spherical();
spherical.set(100 + cubeDim / 2, 0.4, 0);
cubeMesh.position.setFromSpherical(spherical);
var zero = new THREE.Vector3(0, 0, 0);
cubeMesh.lookAt(zero);
scene.add(sphereMesh);
sphereMesh.add(cubeMesh);
initLights();
};
var render = function () {
renderer.render(scene, camera);
};
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
};
init();
animate()
You can test it in my fiddle here
Here is a fiddle where the camera is zoomed a little bit out by clicking the button.
JS Fiddle
var camera, scene, renderer, controls, cubeMesh;
document.querySelector('button').onclick = function () {
let x = cubeMesh.position.x
let y = cubeMesh.position.y
let z = cubeMesh.position.z
camera.position.x = 0
camera.position.y = y + 200
camera.position.z = z + 100
camera.lookAt(controls.target);
};
var initLights = function () {
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);
var light = new THREE.DirectionalLight(0x002288);
light.position.set(-1, -1, -1);
scene.add(light);
var light = new THREE.AmbientLight(0x222222);
scene.add(light);
};
var init = function () {
renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 300;
scene = new THREE.Scene();
controls = new THREE.TrackballControls(camera);
controls.target.set(0, 0, 0);
controls.rotateSpeed = 2;
document.body.appendChild(renderer.domElement);
var sphereGeom = new THREE.SphereGeometry(100, 32, 32);
var sphereMat = new THREE.MeshPhongMaterial({
color: 0xfb3550,
flatShading: true
});
var sphereMesh = new THREE.Mesh(sphereGeom, sphereMat);
//cube
var cubeDim = 20;
var cubeGeom = new THREE.BoxGeometry(cubeDim, cubeDim, cubeDim);
var cubeMat = new THREE.MeshPhongMaterial({
color: 0x7cf93e,
flatShading: true
});
cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
var spherical = new THREE.Spherical();
spherical.set(100 + cubeDim / 2, 0.4, 0);
cubeMesh.position.setFromSpherical(spherical);
var zero = new THREE.Vector3(0, 0, 0);
cubeMesh.lookAt(zero);
scene.add(sphereMesh);
sphereMesh.add(cubeMesh);
initLights();
};
var render = function () {
console.log(camera.position)
renderer.render(scene, camera);
};
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
};
init();
animate()
You have to set the camera target to the position where you want to look at.
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
camera.lookAt(newTarget);
and the THREE.TrackballControls has to be notified to update from the camera THREE.TrackballControls.update:
document.querySelector('button').onclick = function () {
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
If the current camera position should be kept and not be reseted, then the position has to be read form the world matrix of the camera and the initial position of the camera has to be set to its current position:
document.querySelector('button').onclick = function ()
var newPosition = new THREE.Vector3(0, 0, 0);
newPosition.applyMatrix4( camera.matrixWorld );
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.position.copy(newPosition);
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
See the example:
var camera, scene, renderer, controls, cubeMesh;
document.getElementById('reset').onclick = function () {
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
document.getElementById('target').onclick = function () {
var newPosition = new THREE.Vector3(0, 0, 0);
newPosition.applyMatrix4( camera.matrixWorld );
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.position.copy(newPosition);
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
var initLights = function () {
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);
var light = new THREE.DirectionalLight(0x002288);
light.position.set(-1, -1, -1);
scene.add(light);
var light = new THREE.AmbientLight(0x222222);
scene.add(light);
};
var init = function () {
renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 300;
scene = new THREE.Scene();
controls = new THREE.TrackballControls(camera);
controls.target.set(0, 0, 0);
controls.rotateSpeed = 2;
document.body.appendChild(renderer.domElement);
var sphereGeom = new THREE.SphereGeometry(100, 32, 32);
var sphereMat = new THREE.MeshPhongMaterial({
color: 0xfb3550,
flatShading: true
});
var sphereMesh = new THREE.Mesh(sphereGeom, sphereMat);
//cube
var cubeDim = 20;
var cubeGeom = new THREE.BoxGeometry(cubeDim, cubeDim, cubeDim);
var cubeMat = new THREE.MeshPhongMaterial({
color: 0x7cf93e,
flatShading: true
});
cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
var spherical = new THREE.Spherical();
spherical.set(100 + cubeDim / 2, 0.4, 0);
cubeMesh.position.setFromSpherical(spherical);
var zero = new THREE.Vector3(0, 0, 0);
cubeMesh.lookAt(zero);
scene.add(sphereMesh);
sphereMesh.add(cubeMesh);
initLights();
};
var render = function () {
renderer.render(scene, camera);
};
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
};
init();
animate();
button {
position : absolute;
top : 0;
right : 0;
}
.button2 {
position : absolute;
top : 0;
left : 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
<button id="reset" class="button2">
reset camera
</button>
<button id="target">
look at target
</button>

Three.js - Animation is not playing

I have problem with animating object exported via blender plugin from blender to THREE.js. Animation did not start running...
Of course, I tried many combinations of settings when exporting from blender and importing to THREE.js library, but without success.
Here is code, what I think should work. Comment Critical section annotate where is probably some mistake. Link to source JSON is in the example too. Of course, I can provide source *.blend file, if needed...
var tgaLoader = new THREE.TGALoader();
var objectLoader = new THREE.ObjectLoader();
var clock = new THREE.Clock();
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
document.getElementById('container').appendChild(renderer.domElement);
objectLoader.load('//cdn.rawgit.com/PiranhaGreg/files/master/scavenger.json', function (loadedScene) {
scene = loadedScene;
mesh = scene.children[0];
scene.background = new THREE.Color('white');
mesh.material = new THREE.MeshPhongMaterial({ map: tgaLoader.load('//cdn.rawgit.com/PiranhaGreg/files/master/SCA_BODY_V0.TGA') });
hemiLight = new THREE.HemisphereLight('white', 'white', 0.6);
scene.add(hemiLight);
camera = new THREE.PerspectiveCamera(30, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000);
camera.position.set(500, 200, -100);
controls = new THREE.OrbitControls(camera);
controls.target.set(0, 50, 0);
controls.update();
var geometry = new THREE.PlaneBufferGeometry(200, 200);
var material = new THREE.MeshPhongMaterial({ shininess: 0.1 });
var ground = new THREE.Mesh(geometry, material);
ground.rotation.x = - Math.PI / 2;
scene.add(ground);
mesh.scale.set(-1, -1, 1);
// Critical section...
mixer = new THREE.AnimationMixer(mesh);
var sequence = THREE.AnimationClip.CreateFromMorphTargetSequence('animation', mesh.geometry.morphTargets, 25, true);
var animation = mixer.clipAction(sequence);
animation.play();
// End of critital section
animate();
});
window.onresize = function() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
var delta = 0.75 * clock.getDelta();
mixer.update(delta);
renderer.render(scene, camera);
}
body {
margin: 0px;
overflow: hidden;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/TGALoader.js" type="application/javascript"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>
Thanks for any suggestion.
I dug in into animation and noticed that it uses morphTargets. And then I remembered about this example. So, the key moment is to set .morphTarget parameter of a material to true, so, I've applied it to the material in your code snippet and it started to work:
mesh.material = new THREE.MeshPhongMaterial({
map: tgaLoader.load('//cdn.rawgit.com/PiranhaGreg/files/master/SCA_BODY_V0.TGA'),
morphTargets: true
});
Though, I'm not sure, if such an approach is correct, but, at least, it's working )
var tgaLoader = new THREE.TGALoader();
var objectLoader = new THREE.ObjectLoader();
var clock = new THREE.Clock();
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
document.getElementById('container').appendChild(renderer.domElement);
objectLoader.load('//cdn.rawgit.com/PiranhaGreg/files/master/scavenger.json', function (loadedScene) {
scene = loadedScene;
mesh = scene.children[0];
scene.background = new THREE.Color('white');
mesh.material = new THREE.MeshPhongMaterial({ map: tgaLoader.load('//cdn.rawgit.com/PiranhaGreg/files/master/SCA_BODY_V0.TGA'), morphTargets: true });
hemiLight = new THREE.HemisphereLight('white', 'white', 0.6);
scene.add(hemiLight);
camera = new THREE.PerspectiveCamera(30, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000);
camera.position.set(500, 200, -100);
controls = new THREE.OrbitControls(camera);
controls.target.set(0, 50, 0);
controls.update();
var geometry = new THREE.PlaneBufferGeometry(200, 200);
var material = new THREE.MeshPhongMaterial({ shininess: 0.1 });
var ground = new THREE.Mesh(geometry, material);
ground.rotation.x = - Math.PI / 2;
scene.add(ground);
mesh.scale.set(-1, -1, 1);
// Critical section...
mixer = new THREE.AnimationMixer(mesh);
var sequence = THREE.AnimationClip.CreateFromMorphTargetSequence('animation', mesh.geometry.morphTargets, 25, true);
var animation = mixer.clipAction(sequence);
animation.play();
// End of critital section
animate();
});
window.onresize = function() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
var delta = 0.75 * clock.getDelta();
mixer.update(delta);
renderer.render(scene, camera);
}
body {
margin: 0px;
overflow: hidden;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/TGALoader.js" type="application/javascript"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>

ThreeJS - Intersection of a line and sphere

I have two objects on my scene: a red line and a sphere.
While camera rotating/zooming/moving, I need to check the following:
Does the line intersects with the sphere looking from the current position of the camera (please see images below)? Please use this JS fiddle that creates the scene on the images.
I know how to find the intersection between the current mouse position and objects on the scene (just like this example shows).
But how to do this in my case?
JS Fiddle Code:
/**
* PREPARE SCENE
*/
var mouse = {
x : 0,
y : 0
};
var projector = new THREE.Projector();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,
window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = -5;
camera.position.y = 5;
camera.position.z = 30;
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera,
renderer.domElement);
controls.rotateSpeed = 3.0;
controls.zoomSpeed = 1.5;
controls.panSpeed = 1.0;
controls.staticMoving = true;
var grid = new THREE.GridHelper(20, 5);
scene.add(grid);
/**
* CREATE SPHERE
*/
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(5, 10, 10),
new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 8));
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 20));
var line = new THREE.Line(lineGeometry, lineMaterial);
scene.add(line);
renderer.domElement.addEventListener('mousemove', render, false);
render();
function render(event) {
var mouse = {};
/*
* INTERSECTION
*/
if (event != null) {
//intersection job???
}
controls.update();
renderer.render(scene, camera);
}
So, I found the solution that is pretty simple (of course). See new JS Fiddle that checks intersection of the line and sphere and visualizes the ray for debugging.
The JS Fiddle code:
var camera, controls, scene, renderer;
init();
animate();
render();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 800;
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 4;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.addEventListener('change', render);
// world
scene = new THREE.Scene();
sceneTarget = new THREE.Scene();
var grid = new THREE.GridHelper(500, 50);
scene.add(grid);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(100, 200, 100));
lineGeometry.vertices.push(new THREE.Vector3(300, 200, 200));
var line = new THREE.Line(lineGeometry, lineMaterial);
sceneTarget.add(line);
/*
* CREARE SPHERE
*/
var sphere = new THREE.Mesh(new THREE.SphereGeometry(150, 100, 100), new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
// renderer
renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.autoClear = false;
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
}
function render() {
renderer.render(scene, camera);
renderer.render(sceneTarget, camera);
intersect();
}
function intersect() {
var direction = new THREE.Vector3(100, 200, 100);
var startPoint = camera.position.clone();
var directionVector = direction.sub( startPoint );
var ray = new THREE.Raycaster(startPoint, directionVector.clone(). normalize());
scene.updateMatrixWorld(); // required, since you haven't rendered yet
var rayIntersects = ray.intersectObjects(scene.children, true);
if (rayIntersects[0]) {
//inersection is found
console.log(rayIntersects[0]);
//visualize the ray for debugging
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(ray.ray.origin.x, ray.ray.origin.y, ray.ray.origin.z));
geometry.vertices.push(new THREE.Vector3(100, 200, 100));
var line = new THREE.Line(geometry, material);
sceneTarget.add( line );
}
}

Categories

Resources