Im a newbie in 3D computer graphics and seen an odd thing.
I used the XTK-Toolkit, witch is great with DICOM. I add a cube in the scene and translated it far from the center (http://jsfiddle.net/64L47wtd/2/).
when the cube rotate it looks like it is moving
Is this a bug in XTK, or an principle problem with 3D rendering?
window.onload = function() {
// create and initialize a 3D renderer
var r = new X.renderer3D();
r.init();
// create a cube
cube = new X.cube();
// skin it..
cube.texture.file = 'http://x.babymri.org/?xtk.png';
cube.transform.translateX(250);
cube.transform.translateY(200);
cube.transform.translateX(270);
r.add(cube); // add the cube to the renderer
r.render(); // ..and render it
// add some animation
r.onRender = function() {
// rotation by 1 degree in X and Y directions
cube.transform.rotateX(1);
cube.transform.rotateY(1);
};
};
You miss to consider the cube a compound object consisting of several vertices, edges and/or faces. As a compound object it's using local coordinate system consisting of axes X, Y, Z. The actual cube is described internally using coordinates for vertices related to that cube-local coordinate system.
By "translating" you declare those relative coordinates of vertices being adjusted prior to applying inside that local coordinate system. Rotation is then still working on the axes of that local coordinate system.
Thus, this isn't an error of X toolkit.
You might need to put the cube into another (probably fully transparent) container object to translate/move it, but keep rotating the cube itself.
I tried to extend your fiddle accordingly but didn't succeed at all. Taking obvious intentions of X Toolkit into account this might be an intended limitation of that toolkit for it doesn't obviously support programmatic construction of complex scenes consisting of multi-level object hierarchies by relying on its API only.
Related
I'm creating an app where a person (right now I'm using a cone-shape) is standing on some surface (right now I'm using a cylinder laid lengthwise) and I'd like their feet to orient toward some point (right now it's the center of the cylinder).
(edit: I just realized that my Z axis in this photo is pointing in the wrong direction; it should be pointing towards the camera, but the question remains unchanged.)
Here is a version of the code similar to what I'm trying to accomplish. https://codepen.io/liamcorbett/pen/YMWayJ (Use arrow keys to move the cone)
//...
person = CreatePerson();
person.mesh.up = new THREE.Vector3(0, 0, 1);
//
// ...
//
function updateObj(obj, aboutObj=false){
let mesh = obj.mesh;
if (aboutObj) {
mesh.lookAt(
aboutObj.mesh.position.x,
aboutObj.mesh.position.y,
mesh.position.z)
};
}
//
// ...
//
function animate() {
// ...
updateObj(person);
// ...
}
The code above gives me something similar to what I'm looking for, but the issue is that lookAt() seems to always point the local Positive Z-axis in some direction, and I'd much prefer that it point the local Negative Y-axis instead.
I'd prefer to not change the x,y,z axes of the model itself, as I feel that's going to be a pain to deal with when I'm applying other logic to the person object.
Is there a way to change which axis lookAt() uses? Or am I going to have to roll my own lookAt() function? Thanks ~
Is there a way to change which axis lookAt() uses?
No, the default local forward vector for 3D objects (excluding cameras) is (0, 0, 1). Unlike other engines, three.js does not allow to configure the forward vector, only the up vector. But this is not really helpful in your case.
You can try to transform the geometry in order to achieve a similar effect.
If you don't want to do this for some reasons and you still want to use Object3D.lookAt(), you have to compute a different target vector (so not the cylinder's center).
Even if the forward vector of the lookAt method can't be changed (as #Mugen87 said), you can still adjust the local rotation afterwards by knowing in advance the difference between the forward Z axis used, and the axis you consider your mesh to be "upward" (ex: a person standing up on the Y axis).
Basically, in your case, just add this line after the lookAt method :
mesh.rotateOnAxis( new THREE.Vector3(1,0,0), Math.PI * -0.5 );
And the cone will look up :)
I'm am searching for how WebGL / Three.js in general sets their heights and widths.
As in what numbers systems do they use to set x,y,z.
For the Example below, the arrow it pointing straight up with the Y being set to 1 but in pixels it looks like 15- - 200 pixels.
Is there a helper function that i can write that I could pass in 100 for the pixels and it would return me the correct number to float number to use with THREE.js.
Excuse me if I am not talking in correct terms when it comes to number system but this is he only way i know how to reference it at this point.
The only thing i am missing below is creating the scene. but the rest is there, the image shows what it looks lik.
Once again is there a helper function that i can pass pixels to and in return get back the correct number in float for use with THREE.js?
Here is my arrow:
//scene.remove(cube);
scene.remove(group);
// create a new one
var sphere = createMesh(new THREE.SphereGeometry(5, 10, 10));
var cube = createMesh(new THREE.BoxGeometry(6, 6, 6));
sphere.position.set(controls.spherePosX, controls.spherePosY, controls.spherePosZ);
cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ);
// add it to the scene.
// also create a group, only used for rotating
var group = new THREE.Group();
group.add(sphere);
group.add(cube);
scene.add(group);
controls.positionBoundingBox();
var arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), 0, 10, 0x0000ff);
scene.add(arrow);
I receive these JS objects with the Pixels then write to screen, but how do i convert the pixels down to usable units in 3D?
The lengths in 3D do not translate to lengths in 2D uniformly. Especially when perspective projection is employed.
Let's consider your example: Two arrows of the same 3D length and the same orientation would render to different 2D lengths depending on their distance from the camera. The arrow that is closer to camera will be rendered longer than the arrow farther from camera.
In order to maintain a certain pixel length for a certain arrow, you'd have to adjust the 3D length of the arrow every time some parameters of the camera change (e.g. position, orientation, FOV). And also every time the position or orientation of the arrow changes. This is possible (see comment by #WacławJasper ) but rather complicated.
If you could explain the bigger picture of what you wish to achieve there might be a simpler solution to your problem.
I'm having difficulty rotating an object. I am currently using THREE.Shape to configure a custom shape, after creating the shape, I configure it as a Mesh and set the position of it to:
buildingMesh.position.set( -70, -300, levelY );
Now because of the position of the mesh as well as the camera it appears as if its standing up.
Heres what that looks like:
Now I recently added a Orbital camera that rotates around the world axis, once the camera moves, this is how it looks:
Now this makes sense because the y axis was never configured when using the Three.Shape. What I am trying to figure out now is how can I turn that object so it appears to be standing up, as shown in the first image. I have tried using rotation on the x,y,z axis's but it always seems to only rotate within the objects axis.
Any suggestions?
Heres something I tried that I found on another question:
rotateAroundWorldAxis: function(object, axis, radians) {
this.rotWorldMatrix = new THREE.Matrix4();
this.rotWorldMatrix.makeRotationAxis(axis.normalize(), radians);
this.rotWorldMatrix.multiply(object.matrix); // pre-multiply
object.matrix = this.rotWorldMatrix;
object.rotation.setFromRotationMatrix(object.matrix);
}
Try:
mesh.rotate.x = Math.PI // will rotate over x axis 180 degree
where 'mesh' is object you have created (you can rotate 'y' and 'z' too)
So the primary problem here was that the mesh was built by multiple layers. All these layers actually had to be grouped together into an Object3D Which in turn allowed me to simply do: group.rotateOnAxis(axis,Math.pow(Math.PI, 2) / 2);
Hope this helps anyone in the future.
Trying to rotate an object around any axis.
For example like a door hinge (on edge of object) or planet around the sun (outside of object).
The problem seems to be defining the axis. The below unit vector results in axis remaining on object's origin (centre) therefor identical to standard rotation:
object2.rotateOnAxis(new THREE.Vector3(1,0,0), 0.01);
// same as
object1.rotation.x += 0.01;
See code example: JSFiddle
EDIT: Looking for a way that one can rotate around a pivot without using nested children. Rotating a child's parent provides an easy way to manipulate the child's pivot point, but modifying the pivot point is not viable.
Example below, if you wanted to rotate the cube in a figure 8 motion, it would be achievable with this method by changing the parent. But one would have to assure that the new parent's position and orientation is precisely configured to make the child seamlessly jump between parents, and complex motions that do not repeat or loop would be very complicated. Instead, I would like to (and I will paraphrase the question title) rotate an object on a specific axis without using object nesting anywhere in the scene, including outside of the object's mesh.
See code example: JSFiddle with pivots
If you want to rotate an object around an arbitrary line in world space, you can use the following method. The line is specified by a 3D point and a direction vector (axis).
THREE.Object3D.prototype.rotateAroundWorldAxis = function() {
// rotate object around axis in world space (the axis passes through point)
// axis is assumed to be normalized
// assumes object does not have a rotated parent
var q = new THREE.Quaternion();
return function rotateAroundWorldAxis( point, axis, angle ) {
q.setFromAxisAngle( axis, angle );
this.applyQuaternion( q );
this.position.sub( point );
this.position.applyQuaternion( q );
this.position.add( point );
return this;
}
}();
three.js r.85
In Three.JS, I am capable of rotating an object about its origin. If I were to do this with a line, for instance, the line rotates, but the positions of its vertices are not updated with their new locations. Is there some way to apply the rotation matrix to the position of the vertices to find the new position of the point? Say I rotate a line with points at (0,0,0) and (0,100,100) by 45° on the x, 20° on the y, and 100° on the z. How would I go about finding the actual position of the vertices with respect to the entire scene.
Thanks
yes, 'entire scene' means world position.
THREE.Vector3() has a applyMatrix4() method,
you can do the same things that the shader does so in order to project a vertex into world space you would do this
yourPoint.applyMatrix4(yourObject.matrixWorld);
to project that into camera space you can apply this next
yourPoint.applyMatrix4(camera.matrixWorld);
to get an actual screen position in -1 to 1
yourPoint.applyMatrix4(camera.projectionMatrix);
you would access your point like this
var yourPoint = yourObject.geometry.vertices[0]; //first vertex
also, rather than doing this three times, you can just combine the matrices. Didnt test this, but something along the lines of this. Might go the other way:
var neededPVMmatrix = new THREE.Matrix4().multiplyMatrices(yourObject.matrixWorld, camera.matrixWorld);
neededPVMmatrix.multiplyMatrices(neededPVMmatrix, camera.projectionMatrix);
if you need a good tutorial on what this does under the hood i recommend this
Alteredq posted everything there is to know about three.js matrices here
edit
One thing to note though, if you want just the rotation, not the translation, you need to use the upper 3x3 portion which is the rotation matrix, of the models world matrix. This might be slightly more complicated. I forgot what three.js gives you, but i think the normalMatrix would do the trick, or perhaps you can convert your THREE.Vector3() to THREE.Vector4(), and set .w to 0, this will prevent any translation from being applied.
edit2
if you want to move the line point in your example, instead of applying it to the particle, apply it to
var yourVertexWorldPosition = new THREE.Vector3().clone(geo.vertices[1]); //this is your second line point, to whatever you set it in your init function
yourVertexWorldPosition.applyMatrix4();//this transforms the new vector into world space based on the matrix you provide (line.matrixWorld)