how to enable damping without controls.update - three.js

here is my code
when i try to call controls.update() to enable damping all things messed up.i also try control.target but it's not working.if i don't call controls.update() all things work properly.can anyone tell me what should i do
// about direct
points.filter((data) => {
return data.projectDirect === 'aboutDirect'
}).map((projectDirect) => {
projectDirect.element.addEventListener('click', (e) => {
controls.enableRotate = false;
controls.enableZoom = false;
controls.enablePan = false;
e.stopPropagation();
gsap.to(camera.position, {
duration: 1.5,
x: aboutCenter.x + 8,
y: aboutCenter.y,
z: aboutCenter.z,
onUpdate: function () {
camera.lookAt(aboutCenter);
}
});
})
//tick function
const clock = new THREE.Clock()
const tick = () =\> {
const elapsedTime = clock.getElapsedTime()
// controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()

Your code does not work since the result of camera.lookAt(aboutCenter); will be overwritten by controls.update(). Write your GSAP code like so:
gsap.to(controls.target, {
duration: 1.5,
x: aboutCenter.x + 8,
y: aboutCenter.y,
z: aboutCenter.z
});
And update the controls in the animation loop.

Related

How to use Threejs to create a boundary for the Mesh load by fbxloador

The created boundary's scale and rotation are totally different with the import fbxmodel.
Hi, I have loaded a fbx model into the scene by fbxLoador.
const addFbxModel = (modelName: string, position: Vector3) => {
const fbxLoader = new FBXLoader();
fbxLoader.load(
`../../src/assets/models/${modelName}.fbx`,
(fbxObject: Object3D) => {
fbxObject.position.set(position.x, position.y, position.z);
console.log(fbxObject.scale);
fbxObject.scale.set(0.01, 0.01, 0.01);
const material = new MeshBasicMaterial({ color: 0x008080 });
fbxObject.traverse((object) => {
if (object instanceof Mesh) {
object.material = material;
}
});
scene.add(fbxObject);
updateRenderer();
updateCamera();
render();
},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
},
(error) => {
console.log(error);
}
);
};
And now i want to add a click function on this model which will highlight it by showing it's boundary box.
const onclick = (event: MouseEvent) => {
event.preventDefault();
if (renderBox.value) {
const mouse = new Vector2();
mouse.x = (event.offsetX / renderBox.value.clientWidth) * 2 - 1;
mouse.y = -(event.offsetY / renderBox.value.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
const intersect = intersects[0];
const object = intersect.object;
createBoundary(object);
}
}
};
const createBoundary = (object: Object3D) => {
if (object instanceof Mesh) {
console.log(object.geometry, object.scale, object.rotation);
const edges = new EdgesGeometry(object.geometry);
const material = new LineBasicMaterial({ color: 0xffffff });
const wireframe = new LineSegments(edges, material);
wireframe.scale.copy(object.scale);
wireframe.rotation.copy(object.rotation);
console.log(wireframe.scale);
scene.add(wireframe);
}
};
But now the boundary's scale and rotation are totally different with the fbxmodel.
And also the boundary is too complex, is it possible to create one only include the outline and the top point.
Thank you. :)

react magnetic snap scroll with react-scroll

ive got a component where i try to make some sort of magnetic snap scroll. i know the css usual css way of snap-y, and setting snap behavior to smooth, but the snap is too fast. so i tried on my own to create a component where if the app detects a scroll down or up with the function, and a scroll below
const [scrollDir, setScrollDir] = useState("");
const [index, setIndex] = useState("0")
useEffect(() => {
const threshold = 0;
let lastScrollY = window.pageYOffset;
let ticking = false;
const updateScrollDir = () => {
const scrollY = window.pageYOffset;
if (Math.abs(scrollY - lastScrollY) < threshold) {
ticking = false;
return;
}
if(scrollY>lastScrollY){
// setScrollDir("scrolling down")
scroller.scrollTo('about',{
duration: 1000,
delay: 100,
smooth: 'linear',
})
}
// setScrollDir(scrollY > lastScrollY ? "scrolling down" : "scrolling up");
lastScrollY = scrollY > 0 ? scrollY : 0;
ticking = false;
};
const onScroll = () => {
if (!ticking) {
window.requestAnimationFrame(updateScrollDir);
ticking = true;
}
};
window.addEventListener("scroll", onScroll);
console.log(scrollDir);
return () => window.removeEventListener("scroll", onScroll);
}, [scrollDir]);
the magnetic scroll doesnt work, the page goes all jumpy. i could add a global css to make smooth scrolling, but that defeats the purpose of giving easein animation of scrolling. is there a way to work around this?

Make camera fly to object and fit to fiew

I am bit struggle to solve this fit to view object. I want camera fly to a object and centering the screen. Currently just got camera to the object position.
private fitToView = (objSelected: Object3D | undefined) => {
if (objSelected) {
const coord = {
x: this.camera.position.x,
y: this.camera.position.y,
z: this.camera.position.z,
};
this.orbitControl.enabled = false;
const worldPosition = new Vector3();
objSelected.getWorldPosition(worldPosition);
const newCoord = {
x: worldPosition.x,
y: worldPosition.y + 2,
z: worldPosition.z,
};
const tweenCamera = new Tween(coord)
.to(newCoord, 1500)
.easing(Easing.Quadratic.InOut)
.onUpdate(() => {
this.camera.position.set(coord.x, coord.y, coord.z);
})
.onComplete(() => {
this.orbitControl.enabled = true;
this.orbitControl.update();
});
tweenCamera.start();
}
};
This picture I expected fit view after clicking object.

Im trying to make the effect loop with a 'while' and its not working

// API Reference: https://www.wix.com/velo/reference/api-overview/introduction
// “Hello, World!” Example: https://learn-code.wix.com/en/article/1-hello-world
import { timeline } from 'wix-animations';
$w.onReady(function () {
var rotate = true;
let timeline1 = timeline();
while ($w('#image1').onMouseIn(() => {
if (rotate == true) {
timeline1.add($w('#box2'), { opacity: 100, duration: 800, rotate: 3600 }).play();
rotate = false;
} else {
timeline1.replay();
rotate = true;
}
let i=0;
});
Adds an event handler that runs when the element is clicked.
Read more
#param {$w.MouseEvent} event
*/
export function image1_click(event) {
// This function was `added from the Properties & Events panel. To learn more, visit http://wix.to/UcBnC-4
// Add your code for this event here:
}

Drag&Drop element into canvas from HTML

I've got a very trivial task to drag&drop the element from a gallery into the Three.js canvas.
Nothing seems tricky until I face the problem that when I drag the item and add it to the scene I cannot update the item's coordinates until I finish the drag&drop event
I already played around with all events that watch the mouse event mousemove, drag, dragover but the element is just stuck at the initial coordinates, the ones I applied in the dragenter event
export const params = {
devicePixelRatio: Math.min(window.devicePixelRatio, 2),
size: getSizeParams(),
grid: {
size: 20,
divisions: 20,
},
}
const itemProtos = ['Box', 'Sphere', 'Cone']
export const canvas = document.querySelector(`#canvas`)
const raycaster = new Raycaster()
const pointer = new Vector2()
const scene = new Scene()
const camera = new PerspectiveCamera(75, params.size.width / params.size.height, 0.1, 100)
camera.position.z = 5
camera.position.y = 2
/**
* Variable for Drag&Drop - just created object that's being moved around
*/
let newObjectType = null
let newObject = null
/**
* Groups
*/
export const itemGroup = new Group()
scene.add(itemGroup)
/**
* Grid
*/
export const gridHelper = new GridHelper(params.grid.size, params.grid.divisions)
scene.add(gridHelper)
/**
* Renderer
*/
const renderer = new WebGLRenderer({
canvas,
antialias: true,
})
renderer.setSize(params.size.width, params.size.height)
renderer.setPixelRatio(params.devicePixelRatio)
/**
* Resizing updates to fit the screen
*/
window.addEventListener('resize', () => {
params.size = getSizeParams()
camera.aspect = params.size.width / params.size.height
camera.updateProjectionMatrix()
renderer.setSize(params.size.width, params.size.height)
renderer.setPixelRatio()
})
canvas.addEventListener('mouseenter', () => {
canvas.style.cursor = 'grab'
})
/**
* Controls
*/
const orbitControls = new OrbitControls(camera, canvas)
orbitControls.enableDamping = true
orbitControls.addEventListener('start', () => {
canvas.style.cursor = 'grabbing'
})
orbitControls.addEventListener('end', () => {
canvas.style.cursor = 'grab'
})
const tick = () => {
orbitControls.update()
requestAnimationFrame(tick)
renderer.render(scene, camera)
}
window.onload = tick
/**
* Raycaster functions
*/
const refreshMouseCoords = (event) => {
pointer.x = (event.clientX / params.size.width) * 2 - 1
pointer.y = -(event.clientY / params.size.height) * 2 + 1
}
let currentIntersect = null
let currentPick = null
canvas.addEventListener('mousemove', (event) => {
refreshMouseCoords(event)
raycaster.setFromCamera(pointer, camera)
const intersects = raycaster.intersectObjects(itemGroup.children, false)
if(intersects.length && intersects[0].object instanceof Mesh) {
if(!currentIntersect) {
canvas.style.cursor = 'all-scroll'
intersects[0].object.material.color.set('red')
console.log(`mouse enter`)
}
if(currentIntersect && currentIntersect !== intersects[0].object) {
currentIntersect.material.color.set('blue')
intersects[0].object.material.color.set('red')
}
currentIntersect = intersects[0].object
} else {
if(currentIntersect) {
console.log(`mouse leave`)
currentIntersect.material.color.set('blue')
canvas.style.cursor = 'grab'
}
currentIntersect = null
}
moveItem(currentPick)
})
/**
* Function to move items around GridHelper
*/
const moveItem = (item) => {
const intersectsGround = raycaster.intersectObject(gridHelper, false)
if(item && intersectsGround[0]) {
item.position.z = intersectsGround[0].point.z
item.position.x = intersectsGround[0].point.x
}
}
canvas.addEventListener('mousedown', (event) => {
event.preventDefault()
refreshMouseCoords(event)
raycaster.setFromCamera(pointer, camera)
const intersects = raycaster.intersectObjects(itemGroup.children, false)
if(intersects.length && intersects[0].object instanceof Mesh) {
currentPick = intersects[0].object
}
if(currentIntersect) {
canvas.style.cursor = 'all-scroll'
orbitControls.enabled = false
}
})
canvas.addEventListener('mouseup', () => {
if(currentIntersect) {
canvas.style.cursor = 'all-scroll'
orbitControls.enabled = true
}
if(currentPick) {
currentPick = null
}
})
// *** Drag&Drop *** //
const gallery = document.querySelector(`#gallery`)
setGallery(itemProtos, gallery)
canvas.addEventListener('dragenter', (event) => {
event.preventDefault()
console.log('Drag&Drop: dragenter')
refreshMouseCoords(event)
raycaster.setFromCamera(pointer, camera)
const intersects = raycaster.intersectObject(gridHelper)
if (intersects.length && newObjectType) {
add3DEl(intersects[0].point, newObjectType, itemGroup)
}
})
canvas.addEventListener('dragover', (event) => {
event.preventDefault()
event.stopPropagation()
if(newObject) {
moveItem(newObject)
}
})
function setGallery(itemProtos, gallery) {
for (let i of itemProtos) {
const el = createProto()
gallery.appendChild(el)
el.addEventListener('dragstart', function (event) {
event.dataTransfer.setData('text/plain', i)
newObjectType = i
})
el.addEventListener('dragend', function () {
newObjectType = null
newObject = null
})
}
}
function add3DEl({ x, z }, type = 'Box', scene) {
const geometry = new itemObjects[`${type}Geometry`]()
const material = new MeshBasicMaterial({ color: 0x0000ff }) // Shared material for all items
material.wireframe = true
const el = new Mesh(geometry, material)
el.position.x = x
el.position.y = type == 'Sphere' ? 1 : .5
el.position.z = z
el.userData.name = `${type}_${Date.now()}`
newObject = el
scene.add(el)
}
Here you can find a playgroud with what I've got so far: Playground

Resources