I'm trying to build my own camera class in WebGL for learning purposes. It's almost complete but I have 1 slight issue with the lookAt function. If I translate my object in the -z direction then it will work fine but once I move it in the +z direction it acts as if it's doing the opposite and the object will begin to stretch across the screen if I move the camera up or down.
This is what I currently have:
var zAxis = new Vector(cameraPosition.x, cameraPosition.y, cameraPosition.z)
.subtract(target)
.normalize();
var xCross = math.cross(up.flatten(3), zAxis.flatten(3));
var xAxis = new Vector(xCross[0], xCross[1], xCross[2]).normalize();
var yCross = math.cross(zAxis.flatten(3), xAxis.flatten(3));
var yAxis = new Vector(yCross[0], yCross[1], yCross[2]).normalize();
var orientation = [
xAxis.x, xAxis.y, xAxis.z, 0,
yAxis.x, yAxis.y, yAxis.z, 0,
zAxis.x, zAxis.y, zAxis.z, 0,
0, 0, 0, 1
];
var translation = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
cameraPosition.x, cameraPosition.y, cameraPosition.z, 1
];
this.multiply(translation);
this.multiply(orientation);
Does anyone know what I've done wrong?
Related
I have an Object3D (position 10, 0, 30) with a child mesh (local position 0, 0, 0) constructed with BoxGeometry (w: 20, h: 20, d: 20).
Now if a ray is casted with the origin (-10, 0, 0) and direction (1, 0, 0) and checked for intersection, it detected intersection (incorrectly as the object is not in the path).
Consider this code:
const THREE = require('three');
let obj = new THREE.Object3D();
let boxGeo = new THREE.BoxGeometry(20, 20, 20);
let mat = new THREE.MeshPhongMaterial();
let mesh = new THREE.Mesh(boxGeo, mat);
obj.add(mesh);
obj.position.set(10, 0, 30);
let raycaster = new THREE.Raycaster(new THREE.Vector3(-10, 0, 0), new THREE.Vector3(1, 0, 0));
let intersects = raycaster.intersectObject(obj, true);
The intersects array is of length 2 whereas, it should be on length 0.
In order for Raycaster to correctly determine child objects recursively, I had to call updateMatrixWorld() on the parent object before checking intersectionObject.
See a jsfiddle here
I am tweening along a bézier path with 3 points.
// bezier data
var bezierData = {
curviness: 1,
autoRotate: false,
values: [
{x: 0, y: 0, rotation:"40_cw"}, /* <-- The desired state of the object before any animation has happened */
{x: 20, y: 0, rotation:"0_ccw"},
{x: 40, y:0, rotation:"-20_ccw"}
]
};
// build tween
var tween = new TimelineMax()
.add(TweenMax.to("#testobj", 1, {css:{bezier: bezierData}, ease:Power1.easeInOut}));
// create scene
var scene = new ScrollMagic.Scene({
triggerElement: "#testobj",
duration: 100,
offset: 10
})
.setTween(tween)
.addTo(ctrl)
.addIndicators();
What I want: The initial state of my object (i.e. before any animation has happened) should be the first bézier point, {x: 0, y: 0, rotation:"40_cw"}.
What's happening: The initial state is the object's default style, i.e. the equivalent of {x: 0, y: 0, rotation:"0"}. Note how in the jsfiddle the green square starts out upright while I want it to start rotated 40° clock-wise.
Tahir Ahmed's answer works!
perhaps you can use .set() before doing the .to() tween? something like this.
I have created some box geometries in my threejs app and I have successfully drawn a cylinder from the center of one to the center of another using the code below:
function cylinderMesh(pointX, pointY, material) {
var direction = new THREE.Vector3().subVectors(pointY, pointX);
var orientation = new THREE.Matrix4();
orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
orientation.multiply(new THREE.Matrix4(1, 0, 0, 0,
0, 0, 1, 0,
0, -1, 0, 0,
0, 0, 0, 1));
var edgeGeometry = new THREE.CylinderGeometry(2, 2, direction.length(), 8, 1);
var edge = new THREE.Mesh(edgeGeometry, material);
edge.applyMatrix(orientation);
edge.position.x = (pointY.x + pointX.x) / 2;
edge.position.y = (pointY.y + pointX.y) / 2;
edge.position.z = (pointY.z + pointX.z) / 2;
return edge;
}
scene.add(cylinderMesh(vertex1, vertex2, globalMaterial));
My question is: How to I keep the cylinder "connected" to the two vertices I provide if they move?
I don't want to use a THREE.Line because I can't control the width of the line and I have noticed weird issues with clipping if the camera gets too close.
Any ideas?
From a model file object definition the placement a new object is given by a location (a point in space) and the normalized directions of the X-Axis, the Y-Axis and the Z-Axis.
How can i translate this to a THREE.Euler so i can rotate my object correctly in space.
So the axes are off type THREE.Vector3.
If the new object is aligned with the world the values would be:
xAxis = new THREE.Vector3( 1, 0, 0 );
yAxis = new THREE.Vector3( 0, 1, 0 );
zAxis = new THREE.Vector3( 0, 0, 1 );
But if for example the whole local UCS of the object is rotated 180 degrees ( or Math.PI ) around the zAxis they would look like this:
xAxis = new THREE.Vector3( -1, 0, 0 );
yAxis = new THREE.Vector3( 0, -1, 0 );
zAxis = new THREE.Vector3( 0, 0, 1 );
So I need to do something like this:
var object3D = new THREE.Object3D();
object3D.position = location;
var euler = new THREE.Euler();
euler.setFromNormalizedAxes( xAxis, yAxis, zAxis );
object3D.rotation = euler;
Or create a rotation matrix from those axes:
var rotationMatrix = new THREE.Matrix4();
rotationMatrix.setFromNormalizedAxes( xAxis, yAxis, zAxis );
object3D.rotation.setFromRotationMatrix( rotationMatrix, "XYZ" );
I am not so good yet with these rotation matrices and euler rotations...
In the example you gave, the answer would be
object.quaternion.setFromRotationMatrix(
new THREE.Matrix4( -1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 )
);
The columns of the upper 3x3 of the Matrix4 are the new x-, y-, and z-axes.
You could set object.rotation instead. It does not matter.
three.js r.66
I am creating a web page to illustrate the 3D transformations and I am using Three.js. I have detected a problem when I try to do a negative scale in Y axis. In this case, the object is not affected (a face inversion should be done but it doesn't). However, for negative scales in axis X or Z it works well. Any help? This is my code:
var m = new THREE.Matrix4(
scaleX, 0, 0, 0,
0, scaleY, 0, 0,
0, 0, scaleZ, 0,
0, 0, 0, 1
);
cube.applyMatrix(m);
If I use cube.scale.set(scaleX,scaleY,scaleZ) the first transformation is performed rightly, but I can't link with other transformations. I need for my application that the user can do several transformations in the same scene.
Thanks in advance
Your matrix is not correct.
Try with :
var m = new THREE.Matrix4(
1, 0, 0, scaleX,
0, 1, 0, scaleY,
0, 0, 1, scaleZ,
0, 0, 0, 1
);
cube.applyMatrix(m);