0

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

mjkaufer
  • 4,047
  • 5
  • 27
  • 55

1 Answers1

3

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)
pailhead
  • 5,162
  • 2
  • 25
  • 46
  • I have my code at dev.kaufer.org/angle. In the console, when I call `applyRotation(0,Math.PI / 4, 0)`, which rotates the line 45° on the y, the point does not move. However, if I call `applyRotation(0,Math.PI / 2, 0)` again, the particle will then move to the position where it should have been. You can run `applyRotation` to see its code. – mjkaufer Mar 27 '14 at 23:45
  • look at my edit, you need to apply this to your actual vertex that make the line – pailhead Mar 27 '14 at 23:55
  • I've tried that, to no avail. It still seems to do the same thing. – mjkaufer Mar 27 '14 at 23:59
  • I think what's happening is that it's applying the new line point's position, along with its rotation, which is essentially doubling it. – mjkaufer Mar 28 '14 at 00:03
  • I don't even need that particle. Is there a way to get the line's second vertex (i.e. the point not at the origin) into an absolute point, relative to the world position? – mjkaufer Mar 28 '14 at 00:05
  • im somewhat lost, you most likely dont want to actually change the vertex values, you want to save this to a new vector3, and use that information, if you change the vertex itself, then the shader will apply additional transformation, i realize my answer above sounds wrong, ill fix it – pailhead Mar 28 '14 at 00:08
  • I think I've figured out what I'd like. Now, I'm simply applying a new Matrix4 with a desired rotation to `line`. Something like: `var x = new THREE.Matrix4(); x.makeRotationFromEuler(new Three.Vector3(0, Math.PI / 4, 0), "XYZ"); line.geometry.vertices[1].applyMatrix4(x);` I think that works. Time to test it! – mjkaufer Mar 28 '14 at 00:10
  • To clarify, you don't normally update the vertices, at all unless you are actually animating the mesh. That is the whole point of having shaders, parallel processing, gpu, matrices etc. In this case, you want to read the information, that your GPU processes on its own based on the same matrices (before you ever see it on the screen or in world space, youll use JS code above to find out that position in advance) – pailhead Mar 28 '14 at 00:12
  • Ah. I was simply trying to make it so I could track the actual position of the line's vertex. – mjkaufer Mar 28 '14 at 00:13
  • Even simpler version which I believe probably saves a bit of GPU as it's not making a 4x4: `line.geometry.vertices[1].applyEuler(new THREE.Euler(a,b,c,'XYZ'));` – mjkaufer Mar 28 '14 at 00:15
  • you should not do things this way, your vertex still gets processed by the vertex shader which most likely does all the transformations again. Unless you write your own shader that would just pass those values on. – pailhead Mar 28 '14 at 00:24
  • Look at the opengl tutorial, it's the same principle and will give you an excellent insight into whats going on. – pailhead Mar 28 '14 at 00:44