Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perspective #2

Open
desandro opened this issue May 26, 2019 · 7 comments
Open

Perspective #2

desandro opened this issue May 26, 2019 · 7 comments
Labels
feature request New feature or request

Comments

@desandro
Copy link
Member

Currently Zdog uses orthogonal perspective, where all projected lines are parallel with no vanishing point. This works nice with stroke volume — as stroke volume is applied to the entire shape uniformly. So, with the same shape, a corner close to the camera will have the same stroke as the corner far from the camera.

That said, adding perspective would be a good feature to add. It's a relatively low-complexity addition that provides a wide range of capability. Vanishing point perspective is an expected feature of any 3D library. Zdog may be special, but it should get it the same.

Add a 👍 reaction to this issue if you would like to see this feature added. Do not add +1 comments — They will be deleted.

@desandro desandro added the feature request New feature or request label May 26, 2019
@timo-jj
Copy link

timo-jj commented May 28, 2019

Took a look to the doc and If I’m not wrong there is no shadow and light parameter.. It could add a nice depth to the shapes especially if they are moving. Maybe a suggestion to explore :)

@motionarray
Copy link

Yes, this. It'd be great to have shapes change perspective in relationship to where they are on a webpage as you scroll down.

@shaunlebron
Copy link

It's a relatively low-complexity addition

Is it though? How would you draw a simple circle, rotated on any 3D axis? With orthographic, rotated circles are just ellipses. With perspective, you either need a polygon conversion or some way to compute a spline to fit it. ·(I’d be curious to follow the spline math if that’s what you’re thinking)

@jrus
Copy link

jrus commented May 30, 2019

The tricky thing about perspective is that the representation here is cubic Bézier segments. These are affine-invariant, which means that to apply any arbitrary affine transformation we can transform just the control points and the transformation of any arbitrary point on the curve will be correct. That is, if we call our affine transformation A, and our Bézier curve with control points [a, b, c, d] a parametric function f_[a, b, c, d] (t), we have

A(f_[a, b, c, d] (t)) = f_[A(a), A(b), A(c), A(d)] (t)

for every parameter value t. But perspective transformations are not in general affine.

Therefore, to apply a perspective transformation we need to do more work: in general there is no exact Bézier-curve (or multi-segment Bézier spline) representation of a perspective-transformed Bézier curve, so it is necessary to approximate the perspective-transformed curve by multiple Bézier segments to within some desired level of tolerance.

To implement this feature therefore requires (1) an algorithm for determining the control points of the best (or at least some) approximation of a perspective-transformed segment by a single Bézier segment, possibly under some reparametrization, (2) some kind of error metric defining the difference between two curves, (3) some scheme for subdividing the original curve, optionally optimizing the split points to reduce the number of required curves.

It turns out to be just about as easy (or hard) to support applying arbitrary transformation functions as it is to just support perspective transforms.

Let me recommend as one pretty performant method, https://observablehq.com/@jrus/bezplot

@desandro if you want help with this feature shoot me an email or something.

@jrus
Copy link

jrus commented May 30, 2019

It's a relatively low-complexity addition

Is it though? How would you draw a simple circle, rotated on any 3D axis? With orthographic, rotated circles are just ellipses. With perspective, you either need a polygon conversion or some way to compute a spline to fit it. ·(I’d be curious to follow the spline math if that’s what you’re thinking)

Many perspective transformations of circles are ellipses. Of course, if you go far enough you get hyperbolas instead, and then need to approximate those with cubic polynomial segments.

@desandro
Copy link
Member Author

FWIW My approach would be to add a simple scale multiply on render points given the z-distance from the origin. Definitely not mathematically accurate, but it could cover 80% of use cases in like 4 lines of code. Zdog is not trying to be the ultimate 3D engine, more like a lightweight 3D illustration tool.

@benthillerkus
Copy link

So, I've just tried out doing this the super naive way:

let fov = -150;
function scale(z) {return fov/(fov+z)};

And then on each wrapper function for canvas rendering I added:

CanvasRenderer.line = function( ctx, elem, point ) {
  let s = scale(point.z);
  ctx.lineTo( point.x * s, point.y * s);
};

Obviously this can't handle tapering of strokes, setting the fov in the factory / as a property or have the user set custom clipping planes...
Besides that this does work pretty well and I can't really see any weird distortions or wobbles on beziers.

image
image
image

It does however break the cone shape completely (for some reason it even animates itself), produces slight wobbling on Polygons (aka the Z-Dog-Charme) and it pretty much renders every single occlusion hack useless.
image
image

Still I'd be super glad if you've decided to implement this properly and ship it in the next version of Z-Dog ✌

retani added a commit to intergestalt/zdog that referenced this issue May 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request
Development

No branches or pull requests

6 participants