Question

Based on some study of 3D rotation matrixes, I made this jsfiddle, which doesn't quite work on its own, because you can't use 'ctx.getImageData()' on external videos or images (but if you want to try the same code on a locally hosted video source, it should work just fine).

Most of the 3D magic happens in two matrix multiplications. For each point of the image, the xyz coordinates are multiplied by the rotation matrix in the function 'rotatePoint', which transforms the point 'xyz' by the axis of rotation from origin 'p' in the direction of the unit vector 'u' by 'theta' radians.

function rotatePoint(xyz,p,u,rho,phi){
return new Vector(
    ((p.x*(u.y*u.y+u.z*u.z)-u.x*(p.y*u.y+p.z*u.z-u.x*xyz.x-u.y*xyz.y-u.z*xyz.z))*(1-rho)+xyz.x*rho+(-p.z*u.y+p.y*u.z-u.z*xyz.y+u.y*xyz.z)*phi)|0,
    ((p.y*(u.x*u.x+u.z*u.z)-u.y*(p.x*u.x+p.z*u.z-u.x*xyz.x-u.y*xyz.y-u.z*xyz.z))*(1-rho)+xyz.y*rho+( p.z*u.x-p.x*u.z+u.z*xyz.x-u.x*xyz.z)*phi)|0,
    ((p.z*(u.x*u.x+u.y*u.y)-u.z*(p.x*u.x+p.y*u.y-u.x*xyz.x-u.y*xyz.y-u.z*xyz.z))*(1-rho)+xyz.z*rho+(-p.y*u.x+p.x*u.y-u.y*xyz.x+u.x*xyz.y)*phi)|0)
}

Where 'rho' is sin(theta), and 'phi' is cos(theta), and theta is the angle of rotation.

Finally the point is multiplied by the perspective matrix, in the following function, which transforms the point from world coordinates to screen coordinates.

function perspective(xyz){
    return {
    x : ((this.camera.e.z*(xyz.x-this.camera.e.x))/(this.camera.e.z+xyz.z)+this.camera.e.x)|0,
    y : ((this.camera.e.z*(xyz.y-this.camera.e.y))/(this.camera.e.z+xyz.z)+this.camera.e.y)|0
    }
}

Now all of this works just fine for the most part. But for whatever reason, the 3D rotation results in the image repeating off into infinity along the axis of rotation. Here's an example screenshot:

enter image description here

Anyone have any idea why this is happening?

Was it helpful?

Solution

Your rendering function is updating the Z coordinate of your image at each frame.
It makes the rendered image move from frame to frame. You can notice that at the start, when the image rotates until the image orientation stabilizes.

Besides, the algorithm uses the rendering surface itself as a source, so if it runs fast enough it will process the transformed image recursively, leading to the "perspective to infinity" effect.

Finally, it doesnt't check for image space coordinates overflow, leading to wraps when an image border overflows to the next scan line.

The rotation formula seems OK (it indeed rotates a point along the specified axis), but the way it is used is pretty weird.
It does rotate the image along the Y axis, like a reversible blackboard flipping on its hinges, then updates the Z coorinate of the image accordingly. The net result is to stretch the 3D image along the original Z axis.
Combined with the incremental modification of the Z values, this seems to converge toward some fixed stretch/rotation applied to the original image, whose computation is beyond my maths.

The original camera object seems to have been discarded (only the mysterious "e" vector is used, as a kind of perspective projection helper).

I suspect the original code did some basic camera projection, but was then fiddled with beyond my ability to understand what was intended.
At any rate, the code does not do what the comments suggest, and modifying the parameters yield pretty weird results.

I wrote a naive piece of code doing a more traditional camera projection. I tried to keep it readable so it's rather slow. Maybe you can start from there and optimize it to suit your needs.

See a working example here. Requires an HTML5 browser with mp4 support. Tested on latest FireFox.
(it's not a JSfiddle since image safety would not allow to see anything, but the code is inside the page).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top