I'm trying to scale a moving object in THREE, however when I scale it it will scale my object and move it to another position.
I use the following to set the scale of the object
// initiates the scale transition
function doTriangleScale(intersection){
var tween = new TWEEN.Tween(intersection.object.parent.scale)
.to({
x: scaleSize,
y: scaleSize,
z: scaleSize,
}, scaleEase)
tween.start();
// should have a check if the user is still on the object in question, no time for this now
setTimeout(function(){
doTriangleScaleRevert(intersection);
}, 2000)
}
// triggers the scale revert to default
function doTriangleScaleRevert(intersection) {
var tween = new TWEEN.Tween(intersection.object.parent.scale)
.to({
x: 1,
y: 1,
z: 1
}, scaleEase)
tween.start();
}
This works if the objects are not moving about, however my objects ARE moving about with the following code in the render animation
scene.traverse(function (e) {
if (e instanceof THREE.Mesh && e.name != "pyramid") {
e.rotation.x += rotationSpeed;
e.rotation.y += rotationSpeed;
e.rotation.z += rotationSpeed;
if(triangleFloatLeft){
e.position.x += 0.01;
}else{
e.position.x -= 0.01;
}
}
});
I'm looking for a solution that will scale the objects from it's center.
Thanks!
Objects scale around their origin. For example, if you have a cube:
var geo = new THREE.BoxGeometry(1, 1, 1);
If you scale a mesh with geometry geo, it will grow around its center. However if you move the geometry's origin:
geo.applyMatrix(new THREE.Matrix4().makeTranslation(0, 0.5, 0));
Now it will grow upwards, because the origin was moved to the box's floor.
The origin of your object is likely not at its center. You can move the origin either in the model itself (if you imported it) or in Three.js as above.
Related
I'm hoping someone here has done this before. I have a ThreeJS scene, which is essentially a cube. The cube has 6 images one on each of the scenes, basically rendering a 360 panoramic photo.
Within our 3D space, we have 6 cameras, one each pointing at each of the directions, forward, backward, left, right, up, and down. Basically we want to be able to project each of these views all at once.
So, to do this I've made 6 cameras, and added them to the scene. In the scene, we have clickable targets. I want to be able to use ray caster to register a click in any camera view. For example, this is what it looks like:
Within our scene we have clickable hot spots. I want to be able to click on a hotspot on ANY of the 6 cameras. But, I can't get the ray caster to work on even one. This is the code I am using:
if (this._my_cameras && this._my_cameras[0])
{
var mouse = {};
mouse.x = ( this._nextMouseX / this._my_cameras[0].viewport.width ) * 2 - 1;
mouse.y = - ( this._nextMouseY / this._my_cameras[0].viewport.height ) * 2 + 1;
Object.assign(
this._mouse,
coords.normalizeScreenXY(mouse, this._my_cameras[0].viewport)
);
console.log("this._mouse: " + util.inspect(this._mouse));
this._raycaster.setFromCamera(this._mouse, this._my_cameras[0]);
}
else
{
this._raycaster.setFromCamera(this._mouse, this._camera);
}
let intersections = this._raycaster.intersectObjects(
this._scene.children,
true
);
this._nextMouseX / Y are the raw mouse coordinates on screen. My normalize function should normally the mouse coordinates to -1 to 1 as needed. This all works fine if I have one camera taking up the whole view. But with 6 cameras, I never get a ray caster intersection with my targets.
Does anyone have an idea on how to get raycasting or object picking working across multiple cameras?
Edit 1:
This is the code I am now trying to get to work using viewports for the cameras for the raycasting:
for (var i = 0; i < this._igloo_cameras.length; i++)
{
this._mouse.x = ( this._nextMouseX / this._igloo_cameras[i].viewport.w ) * 2 - 1;
this._mouse.y = -1 * (this._nextMouseY / this._igloo_cameras[i].viewport.z) * 2 + 1;
console.log("this._igloo_cameras[i].viewport: " + util.inspect(this._igloo_cameras[i].viewport));
console.log("Igloo Camera #" + i + " this._mouse: " + util.inspect(this._mouse));
this._raycaster.setFromCamera(this._mouse, this._igloo_cameras[i]);
let intersections = this._raycaster.intersectObjects(
this._scene.children,
true
);
all_intersections.push(...intersections);
}
with this I get mouse values outside of 1 to -1 and I still don't get accurate click locations/targets.
This is what I get in my console:
this._igloo_cameras[i].viewport: { x: 0, y: 685, z: 685, w: 685 }
Viewer3D.js:521 Igloo Camera #0 this._mouse: { x: -0.5883211678832116,
y: -1.3649635036496353,
rawX: 141,
rawY: 810 }
Viewer3D.js:520 this._igloo_cameras[i].viewport: { x: 685, y: 685, z: 685, w: 685 }
Viewer3D.js:521 Igloo Camera #1 this._mouse: { x: -0.5883211678832116,
y: -1.3649635036496353,
rawX: 141,
rawY: 810 }
Is it possible to rotate an Object3D object about its end? I found my object's center with const boundingBox = new THREE.Box3().setFromObject(this.object) to determine the center. Would rotating at a point mean translating the object to one point, rotate, then translate back?
Is it possible to rotate an Object3D object about its end?
Yes. By default, Object3D rotates about its center, but it's possible to change rotation point by "wrapping" object in parent (Object3D) and setting position for parent (this will be also a rotation point):
function changeRotationPoint(obj, scene, position) {
// create parent and add it to scene
const parent = new THREE.Object3D();
parent.add(obj);
if (obj.parent) {
obj.parent.add(parent);
} else {
// add to THREE scene if obj doesn't have a
// parent
scene.add(parent);
}
// position for rotation,
// for example (put your data): { x: 0.1, y: 0.1, z: 0 }
parent.position.set(position.x, position.y, position.z);
// correct position of obj, so only rotation point
// will be changed
const x = obj.position.x - position.x,
const y = obj.position.y - position.y,
const z = obj.position.z - position.z
obj.position.set(x, y, z);
}
// call function
changeRotationPoint(this.object, scene, { x: 0.1, y: 0.1, z: 0 });
// rotate this.object
this.object.parent.rotation.set(0.1, 0.2, 0.3);
QUESTION:
I load frontObject onto the scene. I get the centre of said object.
Then I move beyond the object by setting a new point that reuses all the object's centre coordinates except the Z axis (the z coordinate becomes 100), so that I can trace a raycaster from the outside of the character (frontObject) towards it and get the intersection point on the back of the character so that I may place a shield on that point.
Sadly, I get the following output:
CODE:
let box = new THREE.Box3().setFromObject(frontObject);
let sphere = box.getBoundingSphere();
let centerPoint = sphere.center;
backObject.position.set(0,132,-15);
console.log("CENTER POINT X: "+centerPoint.x);
console.log("CENTER POINT Y: "+centerPoint.y);
console.log("CENTER POINT Z: "+centerPoint.z);
centerPoint.z = 100;
var newCoordinate = shootRay(centerPoint, frontObject);
console.log("NEW POINT X: "+newCoordinate.x);
console.log("NEW POINT Y: "+newCoordinate.y);
console.log("NEW POINT Z: "+newCoordinate.z);
function shootRay(center, frontObject) {
var raycaster = new THREE.Raycaster();
var direction = new THREE.Vector3( 0, 0, 1 );
raycaster.ray.direction.copy( direction );
raycaster.ray.origin.copy( center);
var intersects = raycaster.intersectObject(frontObject);
console.log("GO");
if (intersects) {
var point = intersects.point;
console.log("POINT:"+point);
return point;
}
}
EDIT:
https://jsfiddle.net/Username100/y54kpe1h/66/
Your code is somewhat buggy. You'll want to read and address the warnings that you posted.
For var intersects = raycaster.intersectObjects(frontObject); frontObject needs to be an Array like [frontObject] or you need to use the singular intersectObject.
I also recommend using a debugger like the one built in to chrome to put a break point, instead of console.log('POINT , and then seeing what you're getting back from the raycast.
Let me know if this helps...
I'm trying to achieve something similar to an air hockey table effect with Famo.us. The idea is to have multiple circle bodies that can collide (see battle).
Right now my first concern is getting the ball's vector attributes to zero out on drag start.
I'm trying to use the 'reset()' method from Particle.reset, but am running into tons of issues. Here's some of the code from the codepen I have so far:
ball.draggable.on("start", function(pos) {
var zeroV = new Vector(0, 0, 0);
// need to remove force here
ball.circle.reset(pos.position, zeroV, ball.circle.orientation, zeroV);
});
Any idea how to best zero out the force on the ball once I begin a drag? Also how might I determine velocity on release relative to how fast the user is dragging before release?
The answer to both of your questions lie in the adding and removing a body particle from the physics engine in Famo.us.
Here is example code: jsBin code
Note: This example does not solve your whole solution, but does answer your questions and should help you to get to your desired effect.
Any idea how to best zero out the force on the ball once I begin a drag?
Rather than zero out the force, you will detach the particle from the engine temporarily.
physicsEngine.removeBody(this.particle);
In the example, I am doing this on click of a created circle surface.
ball.particle = new Circle({
radius: radius,
position: [x, y, 0]
});
ball.physicsID = physicsEngine.addBody(ball.particle);
physicsEngine.attach(collision, balls, ball.particle);
ball.on('click', function(){
if (!this.stopped) {
physicsEngine.removeBody(this.particle);
} else {
this.physicsID = physicsEngine.addBody(this.particle);
physicsEngine.attach(collision, balls, this.particle);
balls.push(this.particle);
}
console.log('balls', balls);
this.stopped = !this.stopped;
});
How might I determine velocity on release relative to how fast the user is dragging before release?
When you drag the square surface and on('end'... you pass the velocity to the creation of your particle. You use the velocity from the drag end to start your particle in motion with setVelocity.
ball.particle.setVelocity(velocity);
As you can see in the example code:
sync.on('end', function(data){
if (!surface.createdBall && data.velocity){
var velocity = data.velocity;
surface.createdBall = true;
var endX = position[0] + 0;
var endY = position[1] + 0;
createBall(endX, endY, velocity);
}
});
...
function createBall(x, y, velocity) {
var ball = new Surface({
size: [radius * 2, radius * 2],
properties: {
backgroundColor: 'blue',
borderRadius: (radius * 2) + 'px'
}
});
ball.particle = new Circle({
radius: radius,
position: [x, y, 0]
});
ball.physicsID = physicsEngine.addBody(ball.particle);
physicsEngine.attach(collision, balls, ball.particle);
node.add(ball.particle).add(ball);
balls.push(ball.particle);
console.log('created ball', velocity);
ball.particle.setVelocity(velocity);
surface.createdBall = false;
ball.on('click', function(){
if (!this.stopped) {
physicsEngine.removeBody(this.particle);
} else {
this.physicsID = physicsEngine.addBody(this.particle);
physicsEngine.attach(collision, balls, this.particle);
balls.push(this.particle);
}
console.log('balls', balls);
this.stopped = !this.stopped;
});
}
I want to animate a path (actually a set of paths, but I'll get to that) along a curved path.
RaphaelJS 2 removed the animateAlong method, for reasons I haven't been able to discern. Digging into the Raphael documentation's gears demo as abstracted by Zevan, I have got this far:
//adding a custom attribute to Raphael
(function() {
Raphael.fn.addGuides = function() {
this.ca.guide = function(g) {
return {
guide: g
};
};
this.ca.along = function(percent) {
var g = this.attr("guide");
var len = g.getTotalLength();
var point = g.getPointAtLength(percent * len);
var t = {
transform: "t" + [point.x, point.y]
};
return t;
};
};
})();
var paper = Raphael("container", 600, 600);
paper.addGuides();
// the paths
var circ1 = paper.circle(50, 150, 40);
var circ2 = paper.circle(150, 150, 40);
var circ3 = paper.circle(250, 150, 40);
var circ4 = paper.circle(350, 150, 40);
var arc1 = paper.path("M179,204c22.667-7,37,5,38,9").attr({'stroke-width': '2', 'stroke': 'red'});
// the animation
// works but not at the right place
circ3.attr({guide : arc1, along : 1})
.animate({along : 0}, 2000, "linear");
http://jsfiddle.net/hKGLG/4/
I want the third circle to animate along the red path. It is animating now, but at a distance from the red path equal to the third circle's original coordinates. The weird thing is that this happens whether the transform translate in the along object is relative (lowercase "t") or absolute (uppercase "T"). It also always animates in the same spot, even if I nudge it with a transform translation just before the animate call.
Any help very appreciated. I just got off the boat here in vector-land. Pointers are helpful--a working fiddle is even better.
You're just a hop, skip, and jump away from the functionality that you want. The confusion here concerns the interaction between transformations and object properties -- specifically, that transformations do not modify the original object properties. Translating simply adds to, rather than replaces, the original coordinates of your circles.
The solution is extremely straightforward. In your along method:
this.ca.along = function(percent) {
var box = this.getBBox( false ); // determine the fundamental location of the object before transformation occurs
var g = this.attr("guide");
var len = g.getTotalLength();
var point = g.getPointAtLength(percent * len);
var t = {
transform: "...T" + [point.x - ( box.x + ( box.width / 2 ) ), point.y - ( box.y + ( box.height / 2 ) )] // subtract the center coordinates of the object from the translation offset at this point in the guide.
};
return t;
Obviously, there's some room for optimization here (i.e., it might make sense to create all your circles at 0,0 and then translate them to the display coordinates you want, avoiding a lot of iterative math). But it's functional... see here.
One other caveat: the ...T translation won't effect any other transforms that have already been applied to a given circle. This implementation is not guaranteed to play nicely with other transforms.