mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.77k stars 35.38k forks source link

Replicating CSS3D (infinite) perspective #12290

Closed trusktr closed 5 years ago

trusktr commented 7 years ago

The CSS perspective property allows us to define a perspective where a value of 800px means that the camera is "800px away from the Z=0 plane" (whatever that actually means, the spec isn't super clear).

When an object moves away from the camera (negative Z values), it can go infinitely far away and still be rendered (unless it becomes too much smaller than a pixel that it simply can't be blended with colors for that pixel). Furthermore, things disappear when their position + origin offset are equal to the value of perspective (basically, when the object reaches the camera, it disappears if it goes further even if part if it would still be in view).

However, with Three.js PerspectiveCamera (and other WebGL tutorials on perspective) there needs to be a near and far distance specified, and if anything moves beyond that space, it gets clipped. This is unlike CSS perspective, who's far seems to be Infinity, and only a single numerical value needs to be specified.

I'd like to figure out how to effectively produce the same exact sort of perspective as with CSS 3D, in Three.js, so that,

Any pointers on how to do that? I would imagine someone may have already done this before.

trusktr commented 7 years ago

This article shows how to match Three.js perspective onto CSS. I guess I can do it backwards to map from CSS to Three. The only part missing is how to draw infinitely far, or maybe I'm just not getting something yet.

WestLangley commented 7 years ago

11755

trusktr commented 7 years ago

@WestLangley Are you indirectly implying that supporting this feature in glTF automatically means that PerspectiveCamera (or a new class) will have support for infinite perspective? Is there a timeline for this?

I want to learn how to implement this if it isn't planned.

mrdoob commented 7 years ago

Are you aware of how z-buffer works? You're basically asking for Inifinite precision on a z-buffer.

Otherwise we have to check all the objects in a scene (per frame) and adjust the camera accordingly so all the objects fit. However, we wouldn't be able to take into account custom vertex shaders.

trusktr commented 7 years ago

Are you aware of how z-buffer works? You're basically asking for Inifinite precision on a z-buffer.

I'm relatively newb to gl rendering implementations, so I might not be aware of the complexity of implementing this yet. I made polydance after completing the basics at WebGL Fundamentals, but I still have lots to learn. :D

we have to check all the objects in a scene (per frame) and adjust the camera accordingly so all the objects fit.

Seems like a good idea, adapt as the scene changes, perhaps not scanning all objects, but only recording min/max values only when they're updated (f.e. using accessors rather than scan-everything).

Maybe that's why it 'just works' with CSS 3D, because they don't have to account for custom vertex shaders.

But, don't custom vertex shaders risk being clipped by the existing PerspectiveCamera bounds anyways, and updating the bounds wouldn't really be much worse anyways? (f.e. those custom v shaders could be from 3rd party components, and in that case it doesn't really matter what the bounds are, the risk is practically equal, unless the component can inspect and use the existing bounds)

mrdoob commented 7 years ago

we have to check all the objects in a scene (per frame) and adjust the camera accordingly so all the objects fit.

Seems like a good idea, adapt as the scene changes, perhaps not scanning all objects, but only recording min/max values only when they're updated (f.e. using accessors rather than scan-everything).

Wouldn't make it automatic and/or per frame. But maybe a function on Camera that adapts the near and far to the passed scene could be nice.

makc commented 7 years ago

does near / far really make a difference for xy part of projection? I mean, I understand they must be used for z, but I dont see any reason for them to affect xy in any way? did not check the math, just asking.

trusktr commented 7 years ago

@mrdoob

But maybe a function on Camera that adapts the near and far to the passed scene could be nice.

This could mean an extra scene traversal every tick?

Is this doable during the traversal in renderer.render(scene, camera) (I'm still reading, but I'm guessing there's a traversal in there somewhere)?

Maybe we can update something like nearest/furthest values on the scene whenever we update translation of an object in the scene, then for sure we wouldn't need an extra traversal (hmmm, still reading...).


@makc We're just talking about clipping on Z (when objects go beyond the Camera's near and far values on the Z axis).

makc commented 7 years ago

an extra scene traversal every tick?

yes, for every mesh you take geometry bounding sphere, convert to camera coords and do near = min(near, z - radius), far = max (far, z + radius), something like that.

just talking about clipping

this thread started from matching css3d matrix, and that got me thinking if matrices with different near/far actually project the same way

trusktr commented 7 years ago

matrices with different near/far actually project the same way

That's a good question (I'm still learning too!). We can determine this by trying it out. Here's two fiddles, the near far are different (line 21) but they seem to render the same:

So I think changing near/far makes sense for the far values, but negative near values break WebGL rendering:

And very small values for near make WebGL render funky:

@mrdoob What's the best smallest value for near, and why?

As for far seems like it can be any size, and it renders the same.

trusktr commented 7 years ago

As for far seems like it can be any size, and it renders the same.

Well, except if far gets too close to near, obviously:

WestLangley commented 7 years ago

@trusktr Answers to many of your questions can be found in this post.

mrdoob commented 7 years ago

@mrdoob What's the best smallest value for near, and why?

We use 1 unit = 1 meter. So it depends on your scene / use case.