The camera moves around the scene when scrolling THREE.JS GSAP SCROLLTRIGGER - three.js

My problem is when I scroll camera works good but closer to the end its stopping moving smoothly.
At this video I will show how its should work.
I was inspired by this web-site :)
And as I said, I have some little problems..
My glitch code: https://glitch.com/edit/#!/field-polished-border
This how this think is work right now:
gsap.to(camera.position, {
x: 1,
ease: "none",
scrollTrigger:{
trigger: sections[8],
},
})

Your if statements are pretty disorganized, so they eventually start conflicting with each other.
if(scrollTop >= 1400){
// rotate to y: -11
}
else{
// rotate to y: -9.5
}
if(scrollTop >= 3700){
// rotate to y: -12.5
}
This means that when scrollTop reaches 3701, it is both greater than 1400 and 3700, so it'll try to execute both rotations, fighting with each other and giving you glitchy behavior. You should clean up your if statements and make them more organized so they don't contradict each other:
if (scrollTop < 1400){
// rotate to y: -9.5 when less than 1400
}
else if (scrollTop < 3700) {
// rotate to y: -11 when between 1400 and 3700
}
else {
// rotate to y: -12.5 when greater than 3700
}

Related

AFrame & Three.JS detecting collision between moving point and box which happens between frames

I'm trying to implement "bullet and target collision" problem and create an explosion when collision occurs. I managed to do it using aframe-physics-system which was working good: the explosion was rendering at the exact point of the collision and in the exact time. Now I decided to get rid of the physics system as I don't need such overhead - my only goal is to render an explosion.
I tried to use box.containsPoint as well as Raycaster:
tick(time: number, delta: number): void {
// bullet-component
// ...
// Update speed based on acceleration
this.speed = this.currentAcceleration * .01 * delta;
if (this.speed > this.data.maxSpeed) {
this.speed = this.data.maxSpeed;
}
// there is an initial position and direction set in data property.
const newBulletPosition = this.position.add(this.direction.multiplyScalar(this.speed));
// targets is an array of boxes
const found = this._detectCollision(newBulletPosition, this.targets);
if (found) {
console.log("found!");
this.resetBullet();
this.el.emit("collide", {
coordinates: newBulletPosition//found
});
return;
}
this.el.object3D.position.set(newBulletPosition.x, newBulletPosition.y, newBulletPosition.z);
},
_detectCollision(point: THREE.Vector3, obj: THREE.Object3D[]): THREE.Vector3 | null {
const ray = new THREE.Raycaster(point,
this.temps.direction.clone().multiplyScalar(-1).normalize());
const intersects = ray.intersectObjects(obj, true);
return intersects.length % 2 === 1 ? intersects[0].point : null;
},
_box: new THREE.Box3(),
_inverseWorldMatrix: new THREE.Matrix4(),
_detectCollision2(point: THREE.Vector3, obj: THREE.Object3D): THREE.Vector3 | null {
obj.updateMatrixWorld(true);
this._inverseWorldMatrix.copy(obj.matrix).invert();
this._box.setFromObject(obj);
this._inverseBulletPosition.set(point.x, point.y, point.z);
this._inverseBulletPosition.applyMatrix4(this._inverseWorldMatrix);
return this._box.containsPoint(this._inverseBulletPosition);
}
But both approaches have the following flaw:
On frame X the bullet is just in front of a box, but in frame X+1 it is already behind this box. For some reason in this case there might be desirable intersections, but the last bullet position is different than the intersection. Which causes the explosion to be rendered in a wrong position. So, the second approach works only if bullet during it's "jumps" appears inside of a box which is far from being frequent.
The question is how in this case I can repeat the behaviour I had with physics system:
Bullet is moving relatively fast
The intersection is being detected instantly once a bullet crosses any face of a box, so there is no "jump" in bullet's movement.
Thanks in advance.
This is a common problem when trying to recreate the calculations of a physics engine. Since your bullet is too small and sometimes travels beyond the wall in between frames, I see two options:
On frame x+1 you could calculate how much distance has been traveled since frame x, and use that as the size of the bullet. If the plane is crossed in the distance travelled between x -> x1, then you know you've had a collision.
If collision points don't move, you could use a THREE.Raycaster and calculate the point of collision pre-emptively, so you'll know where the bullet will hit before that point is reached:
const raycaster = new THREE.Raycaster();
shoot() {
raycaster.set(origin, direction);
const intersects = raycaster.intersectObjects(arrayOfWalls);
// No intersection took place
if (intersects[0] == undefined) return;
// How far away from origin the collision takes place.
intersects[0].distance;
// The Vector3 where the bullet crosses the wall
intersects[0].point;
}
You can read more about Raycasters in the docs.
Thanks to #Marquizzo, I ended up with the following solution:
I'm casting a ray from the bullet position to the position of the gun. If there is 1 intersection, then the bullet is inside of the box, so I can render an explosion at the intersection position. But if there are two intersections I will take the second one as it will be more far from the ray origin point and hence closer to the gun. But also I had to calculate the distance between the bullet position and the intersection which as was advised should be less than the distance bullet passed between the frames:
tick(time: number, delta: number): void {
const el = this.el;
if (!el) {
console.warn("AFRAME entity is undefined.");
return;
}
this.el.object3D.lookAt(this.direction.clone().multiplyScalar(1000));
// Update acceleration based on the friction
this.temps.position.copy(this.el.object3D.position);
// Update speed based on acceleration
this.speed = this.currentAcceleration * 0.05 * delta;
if (this.speed > this.data.maxSpeed) {
this.speed = this.data.maxSpeed;
}
// Set new position
this.temps.direction.copy(this.direction);
const newBulletPosition = this.temps.position.add(this.temps.direction.multiplyScalar(this.speed));
if (newBulletPosition.length() >= FADE_DISTANCE) {
this.resetBullet();
return;
}
const found = this._detectCollision(newBulletPosition, this.targetCollisionShapes);
if (found) {
const jumpDistance = newBulletPosition.clone().sub(this.el.object3D.position).length();
const collisionDistance = newBulletPosition.clone().sub(found).length();
if (collisionDistance < jumpDistance) {
console.log("found!");
this.resetBullet();
this.el.emit("collide", {
target: this.target,
coordinates: found
} as CollisionEvent);
return;
}
this.el.object3D.position.set(newBulletPosition.x, newBulletPosition.y, newBulletPosition.z);
},
_detectCollision(point: THREE.Vector3, obj: THREE.Object3D[]): THREE.Vector3 | null {
const ray = new THREE.Raycaster(point, this.direction.clone().multiplyScalar(-1).normalize());
const intersects = ray.intersectObjects(obj, true);
return intersects.length % 2 === 1
? intersects[0].point
: intersects.length > 1 ? intersects[1].point : null;
}

How do I use the X and Y values from an object from touches in P5js?

This is my first week playing with P5js and Processing so be gentle.
I've got the following P5js code where I'm looking at touch values. By pressing multi-points on a touch screen brings up more circles anchored to a central position.
What I'd like to know is how do I call the x value for object 1 that's printed in the console? or y value for object 0? how would i state them in the code?
What I'd like to do is use these values to change the dimensions of a shape in the middle of the screen, like something in object 0 driving the height of the shape or object 1 on the the x or y values driving strokeWeight or colour . However I'm in my first week and completely lost to how to use these values in the code.
function setup() {
createCanvas(windowWidth, windowHeight);
background(200);
}
function draw() {
background(255);
fill(255, 0, 0);
strokeWeight(0)
for (var i = 0; i < touches.length; i++) {
fill(255);
strokeWeight(3)
ellipse(touches[i].x, touches[i].y, 50, 50);
line(touches[i].x, touches[i].y, windowWidth / 2, windowHeight / 2);
fill(255);
ellipse(windowWidth / 2, windowHeight / 2, 10, 10);
print(touches);
}
}
// do this prevent default touch interaction
function mousePressed() {
return false;
}
document.addEventListener('gesturestart', function(e) {
e.preventDefault();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.min.js"></script>
or Sketch file is here
any help would be muchly muchly appreciated, i'm a newb trying to find my way
There is only one mistake in it which I found till now, the color of the background and the fill colors are the same! you may change them to actually see the shapes, lines etc.

googlevr/vrview Read position form onGetPosition and set its value for next init

I'm wondering if it is possible (I hope it is) to set init camera rotation read from onGetPosition?
My onGetPosition function look like this:
function onGetPosition() {
console.log({
Yaw: worldRenderer.camera.rotation.y * 180 / Math.PI,
Pitch: worldRenderer.camera.rotation.x * 180 / Math.PI,
x: worldRenderer.camera.rotation.x,
y: worldRenderer.camera.rotation.y,
z: worldRenderer.camera.rotation.z
});
...
}
https://github.com/googlevr/vrview/blob/4e8e57eaddd8e69c8e032a6b5844d4e96af02156/src/embed/main.js#L357
I use this image as a texture:
Initial view, with default_yaw set to 0 degrees looks like this:
In this position onGetPosition returns:
{Yaw: 0, Pitch: -0, x: -0, y: 0, z: -0}
Then I rotate the scene to see this position (about 90 deg to the left):
onGetPosition returns:
{Yaw: 75.66036892219512, Pitch: -42.97581864568984, x: -0.7500695341072581, y: 1.3205225509658982, z: 0.7343037709331535}
I thought that if I set camera rotation inside setDefaultYaw_ function I would see last view so I did this:
WorldRenderer.prototype.setDefaultYaw_ = function(angleRad) {
...
this.camera.setRotationFromEuler(new THREE.Euler(-0.7500695341072581, 1.3205225509658982, 0.7343037709331535, 'XYZ'));
};
https://github.com/googlevr/vrview/blob/2dd890d147f702b9c561694bda5c86575c2a3d44/src/embed/world-renderer.js#L235
Unfortunately nothing happened I still see the view from second image on init.
How can I solve it?

Projecting a point from world to screen. SO solutions give bad coordinates

I'm trying to place an HTML div element over a three.js object. Most stackoverflow solutions offer a pattern similar to this:
// var camera = ...
function toScreenXY(pos, canvas) {
var width = canvas.width, height = canvas.height;
var p = new THREE.Vector3(pos.x, pos.y, pos.z);
var vector = p.project(camera);
vector.x = (vector.x + 1) / 2 * width;
vector.y = -(vector.y - 1) / 2 * height;
return vector;
}
I've tried many variations on this idea, and all of them agree on giving me this result:
console.log(routeStart.position); // target mesh
console.log(toScreenXY(routeStart.position));
// output:
//
// mesh pos: T…E.Vector3 {x: -200, y: 200, z: -100}
// screen pos: T…E.Vector3 {x: -985.2267639636993, y: -1444.7267503738403, z: 0.9801980328559876}
The actual screen coordinates for this camera position and this mesh position are somewhere around x: 470, y: 80 - I determined them by hardcoding my div position.
-985, -1444 are not even close to the actual screen coords :)
Please don't offer links to existing solutions if they follow the same logic as the snippet I provided. I would be especially thankful if someone could explain why I get these negative values, even though this approach seems to work for everyone else.
Here's a couple of examples using the same principle:
Three.js: converting 3d position to 2d screen position
Converting World coordinates to Screen coordinates in Three.js using Projection
Now, I've figured out the problem myself! Turns out, you can't project things before calling renderer.render(). It's very confusing that it gives you back weird negative coords.
Hope other people will find this answer useful.

Programmatically paint an illuminated section of a speedometer

I am trying to make a gauge in Qt Quick that has sections that "light up" from 0 to the needle's position.
One way I can think of doing this is by having an image of the segment and painting it and rotating it many times from code. However, I don't know how this can be done in QML.
It doesn't have to be QML and it doesn't have to be Qt Quick; it could be anything as long as I can use it with Qt and within Qt creator and preferably works accross platforms.
Edit: Made rough sketch but StackOverflow requires me to have 10 reputation to post them, so I am placing links.
No segments illuminated ---------------------------- Some segments illuminated
-
You could easily use a Canvas element to draw an arc stroke with control over its start and end position. Just compose that below the scale of the gauge.
Here is an example how to do that using a value from 0 to 1 to select how "full" the gauge is.
ApplicationWindow {
visible: true
width: 500
height: 500
Canvas {
id: canvas
anchors.fill: parent
rotation: -90
onPaint: {
var c = getContext('2d')
c.clearRect(0, 0, width, height)
c.beginPath()
c.lineWidth = 30
c.strokeStyle = "red"
c.arc(250, 250, 250 - 15, 0, Math.PI * 2 * circ.value)
c.stroke()
}
}
Slider {
id: circ
minimumValue: 0
maximumValue: 1
value: maximumValue / 2
onValueChanged: canvas.requestPaint()
}
}
As requested by Mitch, I explain - the canvas is rotated at 90 CCW degree because of the way Qt draws arcs - they do not start at "12 o'clock" but at 3. You can remove the rotation of the canvas just in case you might want to draw extra stuff, cuz you wouldn't want to make all your drawing offset at 90 degree just to sit right with the rotated canvas, all you need to do to get rid of the rotation is draw the arc in range -Math.PI * 0.5 to Math.PI * 1.5 to account for the art starting at 3 o'clock.

Resources