w3c / fxtf-drafts

Mirror of https://hg.fxtf.org/drafts
https://drafts.fxtf.org/
Other
69 stars 48 forks source link

[geometry] What is the w (perspective) value for? #276

Open dirkschulze opened 6 years ago

dirkschulze commented 6 years ago

Reported by Joe Pea on https://www.w3.org/Bugs/Public/show_bug.cgi?id=30098:

https://drafts.fxtf.org/geometry/#DOMPoint

[[ The following algorithms assume that DOMPointReadOnly objects have the internal member variables x coordinate, y coordinate, z coordinate and >w perspective. ]]

What is the w (perspective) value used for? I would've assumed a point was only an x,y,z triplet. Why is the w needed? And what is a good >value to default to?

If I may guess (let me know how close I am), the perspective value is useful if you are going to call matrixTransform(matrix) and will pass >a matrix that is based on some perspective?

So, for example, if I have a CSS 3D nested DOM hierarchy, where each element in the hierarchy has CSS transform, and the root node has CSS >perspective:1000px, and the root node has only a 2d transform (for example the root node is the body with only width and height applied, it is >drawn in screen CSS pixels, and has perspective applied to it) then if I want to transform a point from the screen coordinates (body client >coordinates) to some point in a nested element inside the 3D space, then would I first multiply the matrices from the nested element up to the >root, then set w on my DOMPoint to 1000, and finally call point.matrixTransform(matrix) where matrix is the nested element's world >matrix that I just calculated?

It would be nice if the geometry-interfaces could link to appropriate articles on how to use the interfaces (not just describe how they are >implemented). Is that something that would be fine to add to the specs?

Maybe I just don't have enough theory background, but I think it would be great to link to relevant articles from the specs.

So far I have a function that I wrote which traverses from a (grandchild)child node somewhere in the DOM "scene graph" up to the root,

function multiply(target) {
   let result = new DOMMatrix;

   while (target && !(target instanceof Scene)) {
       const m = target._calculateMatrix()
       result.preMultiplySelf(m)
       target = target.parent
   }

   return result
}

The Scene instance is just a non-transformed HTMLElement that has perspective:800px applied to it, and all nodes inside the Scene >(including Scene) have transform-style: preserve-3d.

What I am trying to do is map a click event on the screen to a point on the an element that was clicked (clientX and clientY don't work, those >are screen pixel coordinates, not coordinates relative to the clicked element which may be transformed to anywhere in 3D space).

So I thought I could do something like the following where node is a reference to an HTMLElement somewhere inside the "scene graph":

// traverse from nested node to root node and multiply on the way
const matrix = multiply(node)

DOMPoint(clickX, clickY, 0, 800)

Is this how to do it?

I'm implementing DOMPoint.matrixTranform at the moment so that I can try this idea out >(https://github.com/trusktr/geometry-interfaces/blob/master/src/DOMPoint.js). If you have any feedback on that, I would be glad to hear it.

From @zcorpan

Dirk, Rik, can you help with this?

I wouldn't mind the spec having an introductory section or relevant links, or both.

fuchsia commented 6 years ago

Calling w "the perspective" is very confusing, though. As far as I can see, w is just a regular coordinate in ℝ4 and DOMPoints are just four-component vectors (I could store RGBA values in them, if I wanted). And they should be labelled as such - something like:

The x, y, z and w coordinates represent an arbitrary point in a four-dimensional space. By convention, they are treated as a homogeneous representation of points in ℙℝ3 with the Euclidean space embedded at w=1, and the x, y and z coordinates giving the normal three-dimensional position.

AKA It's awfully convenient to do 3D maths in 4D with the fourth coordinate set to 1.