-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
Clipping planes #8465
Clipping planes #8465
Conversation
4f56fd2
to
dc72f2d
Compare
Example (not linked, because it's more of a test and not super pretty-looking) is |
@tschw Sweet! http://ci.threejs.org/api/pullrequests/8465/examples/webgl_clipping_planes.html I think it would be particularly helpful at some point to show in the demo how to specify the clipping plane in world-space, camera-space, and object space. |
Talking about coordinate systems, shadows won't work correctly, I guess: I do it all in view space (because minimum precision in the fragment shader is |
I think in your example, the clipping planes are specified in world space. No? |
Yes, the specification is world space and then I do |
Changed my mind. World-space only is adequate, IMO, which is what you have done. |
Awesome! I was thinking about this just yesterday, and here it is! :-) @WestLangley Shouldn't it be possible to clip a specific object only? Say, to clip a ship while leaving the ocean and skybox alone. |
var N3 = Math.sqrt( 1 / 3 ); | ||
plane1 = new THREE.Plane( new THREE.Vector3( - N3, - N3, - N3 ), 120 ); | ||
plane2 = new THREE.Plane( new THREE.Vector3( 0 , N2 , - N2 ), 90 ); | ||
renderer.userClippingPlanes.push( plane1, plane2 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd call it renderer.clippingPlanes? I like the simple name. Or customClippingPlanes if we need to be more specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I did. It's consistent and not so lengthy.
Thank you @tschw. My comments are not at all requirements, just random feedback. This PR is amazing and we need to get it in. |
World space is the only thing that makes sense API-wise (unless we let the user specify the coordinate system, but that would be over-engineered IMO) and is fairly easy to reach from either of the spaces thanks to Use cases do exist in any of the spaces: Model space: Cut an object for whatever reason - visualization, artistic stuff, or debugging. Shadows must be switchable. In some of these cases we'd want occluders to be cut, in others we wouldn't. |
@@ -49,6 +49,10 @@ THREE.WebGLRenderer = function ( parameters ) { | |||
|
|||
this.sortObjects = true; | |||
|
|||
// user-defined clipping | |||
|
|||
this.userClippingPlanes = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand, this is mainly uniforms. Wouldn't it be better to set this array in the material instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand, this is mainly uniforms. Wouldn't it be better to set this array in the material instead?
This array holds THREE.Plane
objects in world space.
Right now, clipping planes completely mask all rendering - not for a single object, not just for meshes: Points, sprites, meshes, whatever with a built-in shader. Clipping for shadow occlusion must be optional, as discussed above.
The state is global and the resulting uniform value is shared between all materials - similar as we do for the lights (please note that the implementation of the update mechanics are still half-baked in the code here right now - I'm still hardening it).
There are several use cases where it would be cool to allow it on a per object basis. I don't think it really belongs onto the material, but it would be the "reasonably close approximation right now" to avoid issues like #8379 and keep this PR focussed (I guess that's why you are suggesting it?).
Again, as with lighting, there is a conversion to view space in the renderer. This way, there are no problems when running on a platform with reduced fragment shader precision (floats scale nicely around the origin. When they are offset, the exponent gets defined by the translation and there are fewer bits to work with for fine-grained stuff. The nice thing about view space is, that we carry the origin around with us, and everything closely visible is near the origin and thus gets decent precision). So there's a dependence on the camera and putting clipping planes on the material may end up a complication rather than a simplification.
Clipping planes effectively restrict the view frustum, so it's worthwhile to consider putting them on the camera object.
The dream API would have global clipping planes on the camera to mask the viewport - ones that do not affect occluders when rendering a shadow map (just because you can't see the object doesn't mean you can't see its shadow). Then there could be additional ones on an object that semantically cut the object and therefore quite logically also its shadow.
One could then also unify frustum culling (should be a separate PR) by always having six entries minimum - the clipping planes of the camera's view frustum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to investigate what is possible without major changes the renderer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left the planes array on the renderer for now (renamed to .clippingPlanes
). I could fairly easily put the interface on the main camera, but I'm still undecided.
There are several use cases where it would be cool to allow it on a per object basis. I don't think it really belongs onto the material, but it would be the "reasonably close approximation right now" to avoid issues like #8379 and keep this PR focussed (I guess that's why you are suggesting it?).
I guess, I might have guessed wrong. Per-material planes would allow clipping a whole group of objects at once...
Now that the update paths are all working can shape it. In a while - I need to read over it again with a clear mind, maybe clean up a bit and think out how to best implement per-material clipping.
13415dd
to
4babd52
Compare
Here is the revised changeset. What's new?
Fun test:
> plane = new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), 1 )
> renderer.clippingPlanes.push( plane )
> renderer.clipShadows = true
> plane.constant = 0 |
You should be able to do that with separate render passes, I would think. Maybe we should have a
: - ) |
I agree that it would be preferable to somehow be able to clip specific objects. Shadows would at least be tricky to get right with a multipass approach. I think a It's currently rather tricky to implement and better done after some internal issues are resolved (programs must be decoupled from the materials, see #8379). Being able to set extra clipping planes on a material, as suggested by @mrdoob above, would be within reasonable reach, I guess.
What is your motivation of suggesting it? Efficiency or ease of use? Right now, it's technically renderer.clippingPlanes = [];
// ...
renderer.clippingPlanes = myPortalPlanes; Efficiency-wise, I guess it would be nicer to wrap the code in https://github.com/tschw/three.js/blob/ClippingPlanes/src/renderers/WebGLRenderer.js#L1188-L1193 However, an enable flag would require another test in the hot spot (that is frustum culling) with clipping enabled. So in case the suggestion is about efficiency, I'd opt for var clippingPlanesEnabled = this.clippingPlanes.length !== 0; in |
@@ -3,6 +3,7 @@ varying vec3 vNormal; | |||
#include <common> | |||
#include <morphtarget_pars_vertex> | |||
#include <logdepthbuf_pars_vertex> | |||
#incldue <clipping_planes_pars_vertex> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: #incldue
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch! Thanks for spotting.
It was a response to the use case specified by @EliasHasle above. Something like: ocean.layers.set( 0 );
ship.layers.set( 1 );
scene.add( ocean );
scene.add( ship );
...
camera.layers.set( 0 );
renderer.render( scene, camera );
camera.layers.set( 1 );
renderer.clippingEnabled = true;
renderer.render( scene, camera );
renderer.clippingEnabled = false; |
BTW I'd advocate getting this in similar to what @tschw has implemented and then adding further complexity later. I think he has done a good job on the implementation. Yes, it isn't perfectly flexible for all cases but we can add that in later PRs. |
We have object-level clipping, now. API: renderer.clippingPlanes // global clipping planes, do not clip shadows
renderer.localClippingEnabled // enabled local clipping (default false for zero cost)
material.clippingPlanes // local clipping planes...
material.clipShadows // ...clip shadows when this one is set to true (default false)
shaderMaterial.clipping // requests the uniform to be fed to the custom shader |
I was about to suggest that, but it would have been half-baked for certain applications, so couldn't resist. I put some effort into having a clean internal encapsulation to keep it adaptable to future changes. Anyone know whether we have an accessible ?? |
Yes, it was intentional, as the typical use would be to clip the view.
I want to get away from the material-based interface, once the material sharing issue has been resolved. I've been thinking about it for a while now, and believe I can pull it off in a nice way, that is also cleaning up the renderer. But that's clearly something for a different PR - after this one has been merged. So,instead of improving the example, I'd like to improve the API. We could then have a
|
Yes. That would be even better. |
Reading... |
- Scale denormalized but did not scale the position - Projection is not supported (solved by documentation) - Removed unnecessary copying to make up for the normalization - Still arguably too heavy
- GUI dependency of volume visualization on Enabled state - Larger radius for cylindrical global clipping area
Is there actually any interest in merging this one? |
I think this PR is very useful and valuable. Thank you @tschw. I've love to see it merged. |
That sounds great! |
Many thanks! And sorry for the delay 😇 |
Btw, we should consider move all the relevant code to a |
I'd say I described what I'd like do in the next PR in #8552. The factorization would fit in there quite nicely, probably together with other render state stuff currently floating around in locals - we'll see how that one plays out. |
@tschw Hi I am using r77 version. I want to use tranformcontrols for clipping the object by translating or rotating the plane geometry against the object. But the problem is clippingPlanes is taking only THREE.Planes but not Three.Mesh (PlaneGeometry) for which transform controls are not applicable. Is there any solution so that i can translate Three.Plane using transform controls. |
@arunkkarepu For putting it all together you may want to study the source of the |
Is it possible to make the material clippingPlanes property work with a ShaderMaterial? |
Yes, and there's even basic docs. See changes to |
Looked in "Changed files" and found a mention of the boolean clipping parameter but just adding that to my shader material didn't have any effect. I couldn't find the information about the shader code that I need to add to my shader. Do I need to add a uniform for the clipping planes? |
Yes, as for any engine functionality in Three.js, your custom shader needs to implement support for it. |
Also includes my cleanup PR (#8464) - I will take it out, when it turns out necessary.Edit: Took it out.
Adds a property to the render
.userClippingPlanes
, an array that can be filled withTHREE.Plane
objects. All fragments in one half-space defined by each plane are discarded, semantically pretty much like glClipPlane (present in fixed-function desktop OpenGL).See #8462