Difference between BABYLON.Animation and scene.registerBeforeRender - javascript

I just started to learn more about Babylon.js (I don't know if this is a good choice between p5.js and three.js; throw some suggestions for me).
I came along with this question "which function is used more often between BABYLON.Animation and scene.registerBeforeRender(). I guess I am more used to use render() method, but I guess Animation function is good when I change the frameRates.
Which is better? which is used more often ?
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const createScene = () => {
const scene = new BABYLON.Scene(engine);
/**** Set camera and light *****/
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 10, new BABYLON.Vector3(0, 0, 0));
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));
const box = BABYLON.MeshBuilder.CreateBox("box", {});
box.position.y = 0.5;
const ground = BABYLON.MeshBuilder.CreateGround("ground", {width:10, height:10});
// Animations
var alpha = 0;
scene.registerBeforeRender(function () {
box.rotation.y += 0.05;
});
const frameRate = 60;
const xSlide = new BABYLON.Animation("xSlide", "position.x", frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
const keyFrames = [];
keyFrames.push({
frame: 0,
value: 2
});
keyFrames.push({
frame: frameRate,
value: -2
});
keyFrames.push({
frame: 2 * frameRate,
value: 2
});
xSlide.setKeys(keyFrames);
box.animations.push(xSlide);
scene.beginAnimation(box, 0, 2 * frameRate, true);
return scene;
}
const scene = createScene();
engine.runRenderLoop(() => {
// call render method for our scene
scene.render();
});

scene.registerBeforeRender() is more flexible in changing the values. In your example, you are changing rotation by 0.05 constant value. In some cases, this may be variable, so you can assign a variable instead of constant value.
It is tricky to change this in Animation class methods, because in KeyFrame, your key and values are fixed once you set them. The only way I could change this is remove animations and add new ones. On a positive side, in Animation class methods, you can change frameRate and change what you want to do in a particular frame.

Related

Moving Camera from Point A to Point B On the Geometry Created Autodesk Viewer using three js

I am trying move my camera view state from point A to Point B.
For that I am creating a path using LineDashedMaterial in autodesk viewer and I am able to create and show the line from Point A to B.
here is the code
geometry = new THREE.Geometry();
geometry.vertices.push(getBoundingBox([2112]).center(),
getBoundingBox([2109]).center());
material = new THREE.LineDashedMaterial({color: 0xFF0000,
dashSize: 3,
gapSize: 1,
transparent: true,
depthWrite: false,
depthTest: true,
});
checkLineDistance = geometry.computeLineDistances();
geometry.lineDistancesNeedUpdate = true;
NOP_VIEWER.impl.matman().addMaterial('material', material, true);
line= new THREE.Line(geometry, material);
NOP_VIEWER.impl.sceneAfter.skipDepthTarget = true;
NOP_VIEWER.impl.sceneAfter.skipIdTarget = true;
NOP_VIEWER.impl.sceneAfter.add(line);
which has resulted me with:
Now I am stuck with issue where I want to navigate or move my camera as per the direction of my line/path(A to B).
I am using a sample model right now consider this would be a building which have a room A and B.
2.Is there any way I can get all the vectors from where the line is passing I basically need position, target,and upVector for my camera movement
3.Is there any way I can get all the vectors or points from A to B using dbid in forge viewer api
4.I tried putting up Three.js with forge viewer but it seems difficult though.
This is what actually I am trying to achieve but instead of that moving geometry I need to show viewport in forge viewer
The navigation system in Forge Viewer supports a smooth, linear interpolation into custom camera state using the setRequestTransition method, for example, like so:
let newCameraPosition = new THREE.Vector3(1.0, 2.0, 3.0);
let newCameraTarget = new THREE.Vector3(4.0, 5.0, 6.0);
let fov = viewer.navigation.getHorizontalFov();
viewer.navigation.setRequestTransition(true, newCameraPosition, newCameraTarget, fov);
The default duration of this transition is 1 second, so if you had a list of vertices of a path that you would like to follow with the camera, you could do it with something like this:
function followPath(viewer, vertices, delayMs) {
let index = 0;
let timer = setInterval(function () {
if (index >= vertices.length) {
clearInterval(timer);
return;
}
let newPos = vertices[index];
let newTarget = vertices[index + 1];
if (!newTarget) {
let oldPos = viewer.navigation.getPosition();
let oldTarget = viewer.navigation.getTarget();
newTarget = new THREE.Vector3(
newPos.x + (oldTarget.x - oldPos.x),
newPos.y + (oldTarget.y - oldPos.y),
newPos.z + (oldTarget.z - oldPos.z)
);
}
viewer.navigation.setRequestTransition(true, newPos, newTarget, viewer.navigation.getHorizontalFov());
index++;
}, delayMs);
}
followPath(viewer, [
new THREE.Vector3(10, 20, 30),
new THREE.Vector3(40, 50, 60),
new THREE.Vector3(70, 80, 90),
new THREE.Vector3(0, 10, 0)
], 2000);
If you need more flexibility (e.g., interpolating around curves, custom ease-in/ease-out, etc.), you can still use three.js or other animation libraries, and simply control the camera position and target yourself.

How to fully clean up the context and canvas in three.js

We have an application that also runs on an iPad. Using three.js r100.
It has a "main" and several "popups", each with its own canvas, scene and renderer. The "main" has a scene etc. too that is always shown.
To avoid memory issues, we create all the objects when the popup is opened, and clean up when the popup is closed.
But on the iPad, the webinfo still shows the canvasses of closed popups.
And after opening/closing several popups we get an error about too many contexts ("There are too many active WebGL contexts on this page, the oldest context will be lost.").
The first context that is lost is the "main" scene. After that, the system tries to loose a "popup" context. A second error is shown: "WebGL: INVALID_OPERATION: loseContext: context already lost". That seems logical because we did a forceContextLoss() when closing the popup.
At popup close we:
dispose everything (material etc.) in the scene
dispose the OrbitControl
dispose the renderer
forceContextLoss() the renderer
remove the canvas from the DOM
I suspect the canvas is keeping the contexts from being cleaned up, but maybe I miss something?
So, how can we fully remove the contexts of the popups?
Thanks, Willem
Not sure this is a direct answer but I think you will have better luck either
(a) using a single context and the scissor test to emulate multiple canvases (recommended)
See techniques like this
or
(b) using a virtual webgl context that simulates multiple contexts on top of a single context.
Where you really only have 1 context and others are virtual
AFAIK there is no way to force the browser to free a context. Even forcing a context lost is not guaranteed to get rid of the WebGLRenderingContext object, in fact it explicitly does not. When you get a context lost event you keep using the same context object even after restoring.
So, there's no guarantee the browser isn't just going to delete the oldest context as soon as the 9th context is created (or whatever the limit is). The only guarantee is generally when new contexts are created only old ones lose theirs.
Whether it's the context least recently used or the oldest context or the context will the least resources or the context with no more references is up to the browser. Really there is no easy way for the browser to know which contexts to free.
Here's a quick test of creating and deleting contexts. The oldest context gets lost as the 17th context is created on Chrome desktop
'use strict';
/* global THREE */
function makeScene(canvas, color = 0x44aa88, timeout = 0) {
const renderer = new THREE.WebGLRenderer({canvas: canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const material = new THREE.MeshPhongMaterial({color});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
let requestId;
function render(time) {
time *= 0.001; // convert time to seconds
cube.rotation.x = time;
cube.rotation.y = time;
renderer.render(scene, camera);
requestId = requestAnimationFrame(render);
}
requestId = requestAnimationFrame(render);
if (timeout) {
setTimeout(() => {
cancelAnimationFrame(requestId);
canvas.parentElement.removeChild(canvas);
// manually free all three objects that hold GPU resoucres
geometry.dispose();
material.dispose();
renderer.dispose();
}, timeout);
}
}
makeScene(document.querySelector('#c'));
let count = 0;
setInterval(() => {
console.log(++count);
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
makeScene(canvas, Math.random() * 0xFFFFFF | 0, 500);
}, 1000);
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>
Here's the same test with virtual-webgl
'use strict';
/* global THREE */
function makeScene(canvas, color = 0x44aa88, timeout = 0) {
const renderer = new THREE.WebGLRenderer({canvas: canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const material = new THREE.MeshPhongMaterial({color});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
let requestId;
function render(time) {
time *= 0.001; // convert time to seconds
cube.rotation.x = time;
cube.rotation.y = time;
renderer.render(scene, camera);
requestId = requestAnimationFrame(render);
}
requestId = requestAnimationFrame(render);
if (timeout) {
setTimeout(() => {
cancelAnimationFrame(requestId);
// take the canvas out of the dom
canvas.parentElement.removeChild(canvas);
// manually free all three objects that hold GPU resoures
geometry.dispose();
material.dispose();
// hold on to the context incase the rendered forgets it
const gl = renderer.context;
// dispose the rendered in case it has any GPU resources
renderer.dispose();
// dispose the virutal context
gl.dispose(); // added by virtual-webgl
}, timeout);
}
}
makeScene(document.querySelector('#c'));
let count = 0;
setInterval(() => {
console.log(++count);
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
makeScene(canvas, Math.random() * 0xFFFFFF | 0, 500);
}, 1000);
<canvas id="c"></canvas>
<script src="https://greggman.github.io/virtual-webgl/src/virtual-webgl.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>

Changing color of material in babylon.js

I am just getting into babylon.js, but I can't seem to figure out, how would you change color of a material ?
My code currently is:
/* eslint-disable */
import * as BABYLON from 'babylonjs';
// Get the canvas element from our HTML above
const canvas = document.getElementById("root");
// Load the BABYLON 3D engine
const engine = new BABYLON.Engine(canvas, true);
let fn;
let mainColor = new BABYLON.Color3(1.0, 0.2, 0.7);
setTimeout(() => {
mainColor = new BABYLON.Color3(0.3, 0.2, 0.2);
fn();
}, 2000);
// This begins the creation of a function that we will 'call' just after it's built
function createScene () {
// Now create a basic Babylon Scene object
const scene = new BABYLON.Scene(engine);
// Change the scene background color to green.
scene.clearColor = new BABYLON.Color4(0.5, 0.8, 0.6, 0.8);
// This creates and positions a free camera
const camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1, 0.8, 30, new BABYLON.Vector3(0, 0, 0), scene);
// This targets the camera to scene origin
camera.setTarget(BABYLON.Vector3.Zero());
// This attaches the camera to the canvas
camera.attachControl(canvas, false);
// This creates a light, aiming 0,1,0 - to the sky.
const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(1, 1, 1), scene);
// Dim the light a small amount
light.intensity = .5;
// Let's try our built-in 'sphere' shape. Params: name, subdivisions, size, scene
const sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
const materialSphere1 = new BABYLON.StandardMaterial("texture1", scene);
materialSphere1.alpha = 1;
materialSphere1.diffuseColor = mainColor;
sphere.material = materialSphere1;
sphere.position.y = 1;
// Move the sphere upward 1/2 its height
// Let's try our built-in 'ground' shape. Params: name, width, depth, subdivisions, scene
const ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
fn = () => {
materialSphere1.diffuseColor = mainColor;
}
// Leave this function
return scene;
}; // End of createScene function
const scene = createScene();
engine.runRenderLoop(function () {
scene.render();
});
window.addEventListener("resize", function () {
engine.resize();
});
It looks aweful to me. As you can see i am defining fn inside the createScene which then allows me to modify it that way, however I believe that there should be a better way of doing it. I tried creating a function outside the createScene(), that would fetch the color, and then use that for materialSphere1.diffuseColor, however that did not work. So my question is: Is there any other (nicer) way to change a color of a material in babylon.js
Why not declaring your material outside of the callback?
You can also use scene.materials to browse materials

threejs getImageData video performance

Edit;
working codepen (need to provide video file to avoid cross-origin policy)
https://codepen.io/bw1984/pen/pezOXm
I am attempting to modify the excellent rutt etra example here https://airtightinteractive.com/demos/js/ruttetra/ to work for video (still using threejs) and am encountering strange issues with performance.
My code currently works as expected, and actually runs quite smoothly on chrome on my macbook pro, but seems to cause some sort of slow memory leak which i assume is to do with all the heavy lifting which is having to be done by getImageData. Strangely enough its only noticeable once i attempt to refresh the tab, so looks like it may be related to the garbage collection in chrome maybe? anyway to shunt the grunt work onto the GPU instead of killing the CPU?
I just wondered if i am missing anything obvious in terms of code optimisation or if the performance issues i am facing are to be expected given the nature of what i am trying to do.
I am only interested in WebGL / chrome functionality so dont really need to worry about browser compatibility of any kind.
<script>
var container, camera, scene, renderer, controls;
// PI
var PI = Math.PI;
var TWO_PI = PI*2;
// size
SCREEN_WIDTH = window.innerWidth;
SCREEN_HEIGHT = window.innerHeight;
SCREEN_PIXEL_RATIO = window.devicePixelRatio;
// camera
var VIEW_ANGLE = 45;
var ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT;
var NEAR = 0.1;
var FAR = 20000000;
// video raster
var video;
var videoImage;
var videoImageContext;
var _imageHeight;
var _imageWidth;
// lines
var _lineGroup;
// gui
var _guiOptions = {
stageSize: 1,
scale: 1.0,
scanStep: 5,
lineThickness: 10.0,
opacity: 1.0,
depth: 50,
autoRotate: false
};
// triggered from audio.php getMediaStream
function runme()
{
console.log('runme running');
init();
animate();
}
runme();
function init()
{
container = document.createElement('div');
document.body.appendChild(container);
//----------
// scene
//----------
scene = new THREE.Scene();
//----------
// camera
//----------
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
//camera.position.set(0,0,450);
camera.position.set(0,150,300);
//----------
// objects
//----------
// create the video element
video = document.createElement('video');
// video.id = 'video';
// video.type = ' video/ogg; codecs="theora, vorbis" ';
video.src = 'data/sintel.ogv';
//video.src = 'data/az.mp4';
video.load(); // must call after setting/changing source
video.play();
videoImage = document.createElement('canvas');
//videoImage.width = 480;
//videoImage.height = 204;
videoImageContext = videoImage.getContext('2d');
_imageWidth = videoImage.width;
_imageHeight = videoImage.height;
//videoImageContext.fillStyle = '#ffffff';
//videoImageContext.fillRect(0, 0, videoImage.width, videoImage.height);
//----------
// controls
//----------
controls = new THREE.OrbitControls(camera);
//----------
// events
//----------
window.addEventListener('resize', onWindowResize, false);
//----------
// render
//----------
var args = {
//antialias: true // too slow
}
renderer = new THREE.WebGLRenderer(args);
renderer.setClearColor(0x000000, 1);
renderer.setPixelRatio(SCREEN_PIXEL_RATIO); //Set pixel aspect ratio
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
// attach to dom
container.appendChild(renderer.domElement);
//render();
}
function render()
{
if(video.readyState === video.HAVE_ENOUGH_DATA && !video.paused && !video.ended) // and video.currentTime > 0
{
//_imageWidth = videoImage.width;
//_imageHeight = videoImage.height;
videoImageContext.drawImage(video,0,0,_imageWidth,_imageHeight);
// Grab the pixel data from the backing canvas
var _data = videoImageContext.getImageData(0,0,videoImage.width,videoImage.height).data;
//log(data);
//_pixels = data;
var x = 0, y = 0;
if(_lineGroup)
{
scene.remove(_lineGroup);
//_lineGroup = null;
}
_lineGroup = new THREE.Object3D();
var _material = new THREE.LineBasicMaterial({
color: 0xffffff,
linewidth: _guiOptions.lineThickness
});
// loop through the image pixels
for(y = 0; y < _imageHeight; y+= _guiOptions.scanStep)
{
var _geometry = new THREE.Geometry();
for(x=0; x<_imageWidth; x+=_guiOptions.scanStep)
{
var color = new THREE.Color(getColor(x, y, _data));
var brightness = getBrightness(color);
var posn = new THREE.Vector3(x -_imageWidth/2,y - _imageHeight/2, -brightness * _guiOptions.depth + _guiOptions.depth/2);
//_geometry.vertices.push(new THREE.Vertex(posn));
_geometry.vertices.push(posn);
_geometry.colors.push(color);
_color = null;
_brightness = null;
_posn = null;
}
// add a line
var _line = new THREE.Line(_geometry, _material);
//log(line);
_lineGroup.add(_line);
// gc
_geometry = null;
}
scene.add(_lineGroup);
_data = null;
_line = null;
}
renderer.render(scene,camera);
}
function animate(){
requestAnimationFrame(animate);
stats.update();
render();
}
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
// Returns a hexadecimal color for a given pixel in the pixel array.
function getColor(x, y, _pixels)
{
var base = (Math.floor(y) * _imageWidth + Math.floor(x)) * 4;
var c = {
r: _pixels[base + 0],
g: _pixels[base + 1],
b: _pixels[base + 2],
a: _pixels[base + 3]
};
return (c.r << 16) + (c.g << 8) + c.b;
}
// return pixel brightness between 0 and 1 based on human perceptual bias
function getBrightness(c)
{
return ( 0.34 * c.r + 0.5 * c.g + 0.16 * c.b );
}
</script>
any help anyone could provide would be much appreciated, even if its just pointing me in the right direction as i am only just beginning to experiment with this stuff and have almost given myself an aneurysm trying to wrap my tiny mind around it.
The slow memory leak is most likely due to:
// add a line
var _line = new THREE.Line(_geometry, _material);
//log(line);
_lineGroup.add(_line);
THREE.Line is an object, containing other objects and lots of data. Every time you instantiate it, it creates .matrix, .matrixWorld, .modelViewMatrix, .normalMatrix which are all arrays with a bunch of numbers. .position,.quaternion, .scale, .rotation and probably .up are vectors,quats etc. and are slightly smaller but also arrays with special constructors.
Allocating all this every 16 miliseconds only to be released the next frame is probably the cause of your "leak".
You should create a pool of THREE.Line objects, and draw that every frame instead. The number of drawn objects you can control with .visible and mutate their transformation properties.
#pailhead I took your advice about pre-rendering the lines and lineGroup in advance and then updating the vertices on each animation frame instead and now its purring like a kitten. Also needed to insert the following line to make sure updated coords are picked up;
e.geometry.verticesNeedUpdate = true;
I cant figure out how to get a hosted video to work on codepen (cross-origin policy violation issues) but i have put a version up anyway to show the working code.
https://codepen.io/bw1984/pen/pezOXm
I will try to get a self-hosted (working) version up as soon as i can
I've been trying in vain to get colour working, but that will have to be an exercise for another day.

3DObject event handler selecting nearby objects, should select self Three.js

I have been digging into the documentation, tutorials, stackoverflow questions literally all day and cannot find the solution to this problem. Please please take pity on me and help me!
I have a watering can that I put an event listener on, but on mousedown, objects near and to the left get selected ie. the tree trunk or a leaf (code not included) and then I am able to drag and drop that object around until I put it down and it is out of range of the watering can. If I drop it near the watering can, it will get selected again when I click. This is NOT the intended behavior, I want the actual watering can I clicked to be selected and then proceed to get dragged and dropped etc. There is kind of a lot of code here but I am not sure where the problem lies anymore so I am including almost all of it. It's like the watering can thinks it is elsewhere or the ray thinks it is shooting elsewhere. PLEASE TELL ME IF I CAN CLARIFY ANYTHING OR SEND MORE CODE. I just started learning three.js yesterday so there are definitely things I don't understand but I am pretty clear on what is supposed to be happening here... and this is not it :D
const WateringCan = function() {
this.mesh = new THREE.Object3D();
const mat = new THREE.MeshStandardMaterial({ metalness: 0.8, color: 0xadb2bd });
// Create the can
const geomCan = new THREE.CylinderGeometry(15, 15, 25, 10, 10);
geomCan.applyMatrix( new THREE.Matrix4().makeScale(1.1, 1.0, 0.6));
geomCan.computeBoundingBox();
geomCan.computeFaceNormals();
const can = new THREE.Mesh(geomCan, mat);
can.castShadow = true;
can.receiveShadow = true;
this.mesh.add(can);
// Create the handle
const geomHandle = new THREE.TorusGeometry( 10, 2, 8, 6, Math.PI);
geomHandle.applyMatrix( new THREE.Matrix4().makeScale(0.9, 1.1, 1.0));
const handle = new THREE.Mesh(geomHandle, mat);
handle.rotation.z = 4.5;
handle.position.x = 13.5;
handle.castShadow = true;
handle.receiveShadow = true;
this.mesh.add(handle);
// Create spout
const geomSpout = new THREE.CylinderGeometry(1, 3, 20, 5, 5);
const spout = new THREE.Mesh(geomSpout, mat);
spout.rotation.z = 1;
spout.position.x = -22;
spout.position.y = 10;
spout.position.z = 3;
spout.castShadow = true;
spout.receiveShadow = true;
this.mesh.add(spout);
const domEvents = new THREEx.DomEvents(camera, renderer.domElement);
domEvents.addEventListener(can, 'mousedown', (e) => onWateringCanMouseDown(e));
};
let wateringCan;
function createWateringCan() {
wateringCan = new WateringCan();
wateringCan.name = "wateringCan";
wateringCan.mesh.position.x = 120;
wateringCan.mesh.position.y = -30;
wateringCan.mesh.position.z = -10;
scene.add(wateringCan.mesh);
objects.push(wateringCan.mesh);
}
let plane;
function createPlane() {
plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(WIDTH, HEIGHT, 8, 8), new THREE.MeshBasicMaterial({ color: 0xffffff, alphaTest: 0, visible: false }));
scene.add(plane);
}
let selection;
function onWateringCanMouseDown(e) {
const mouseX = (e.clientX / WIDTH) * 2 - 1;
const mouseY = -(e.clientY / HEIGHT) * 2 + 1;
const mouse3D = new THREE.Vector3(mouseX, mouseY, 0.5);
mouse3D.unproject(camera);
raycaster.set(camera.position, mouse3D.sub(camera.position).normalize());
const intersectedObjects = raycaster.intersectObjects(objects, true);
if (intersectedObjects.length > 0) {
selection = intersectedObjects[0].object;
const intersectPlane = raycaster.intersectObject(plane);
offset.z = selection.position.z;
offset.copy(intersectPlane[0].point).sub(plane.position);
}
}
function onDocumentMouseMove(e) {
const mouseX = (e.clientX / WIDTH) * 2 - 1;
const mouseY = -(e.clientY / HEIGHT) * 2 + 1;
const mouse3D = new THREE.Vector3(mouseX, mouseY, 0.5);
mouse3D.unproject(camera);
raycaster.set(camera.position, mouse3D.sub(camera.position).normalize());
raycaster.setFromCamera( mouse3D.clone(), camera);
if (selection) {
offset.z = selection.position.z;
const intersectPlane = raycaster.intersectObject(plane);
selection.position.copy(intersectPlane[0].point.sub(offset));
} else {
const intersectedObjects = raycaster.intersectObjects(objects);
if (intersectedObjects.length > 0) {
plane.position.copy(intersectedObjects[0].object.position);
plane.lookAt(camera.position);
}
}
}
function onDocumentMouseUp(e) {
selection = null;
}
Things I have already tried: computeBoundingBox() on everything I have applyMatrix on, refactoring mouse3D/raycaster around in slightly different ways, moving the can far away (then nothing gets selected). I also had the event listener set on the document for a while and I did not have this problem, but the watering can pieces did not stick to each other, the individual spout/can/handle would get dragged and dropped. But at least it knew then that I was clicking on them! Also having the ability to drag and drop literally everything on the page was fun but also not the point, like I don't need all the leaves on my tree to move around.
Please please help me if you can!! I have been messing around with this all day and it is killing my soul. :D
Okay, so. I did not find out what the reason behind this strange behavior was so I decided to kind of restructure what I was doing and I am no longer having this problem.
What I did is:
removed the event listener from the watering can and put it back on the document
removed all objects but the watering can from my objects array that gets looked through on raycaster.intersectObjects so now nothing but that can be dragged and dropped
things are mostly fine now

Categories