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

Fix clipping in webgl2_materials_texture3d #22649

Merged
merged 3 commits into from
Oct 8, 2021
Merged

Conversation

rlschuller
Copy link
Contributor

Description

The camera position was too close to the 3D texture, causing clipping
from certain angles.

Before the repositioning:
threejs_before

After the repositioning:
threejs_after

The camera position was too close to the 3D texture, causing clipping
from certain angles.
@Mugen87
Copy link
Collaborator

Mugen87 commented Oct 6, 2021

https://threejs.org/examples/webgl2_materials_texture3d
https://raw.githack.com/rlschuller/three.js/dev/examples/webgl2_materials_texture3d.html

TBH, I don't see how the PR improves the example. Do you mind explaining the mentioned clipping in more detail?

@rlschuller
Copy link
Contributor Author

Sure ;)

When rotating along the axis parallel to a horizontal line in the monitor, the extremities of the 3D texture can get clipped. In this particular model, it affects mostly the pelvic bone:
clipping

Setting the x position of the camera to -256 seems to move the model forward relatively to the camera and fix the clipping:
after

Move the object to the middle of the frustrum and make the depth of the
frustrum bigger.
@rlschuller
Copy link
Contributor Author

The last commit just increase the size of the frustrum and move the object to the middle of it.

Moving the object a bit makes the frustrum positioning more apparent.

Before:
before

After:
after

camera = new THREE.OrthographicCamera( - h * aspect / 2, h * aspect / 2, h / 2, - h / 2, 1, 1000 );
camera.position.set( 0, 0, 128 );
camera = new THREE.OrthographicCamera( - h * aspect / 2, h * aspect / 2, h / 2, - h / 2, 1, 2000 );
camera.position.set( -1000, 0, 128 );
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would camera.position.set( 0, 0, 256 ) work too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes the camera higher, which would keep the object further away than using camera.position.set( 0, 0, 128 ). From what I understood, what matters is the initial Euclidean distance from the camera to the object's center.

I believe that it would fix the clipping due to rotation only, but not for rotation + horizontal movement.

With the frustrum size of 1000-1=999 (before), I couldn't find a distance that would reliably avoid clipping for rotation + horizontal movement. Either it would clip at the front or at the back.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zooming also doesn't seem to affect the frustrum's near and far planes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let OOO be the object and C the camera.

changing only camera.position.set( 0, 0, 128 ); to camera.position.set( 0, 0, 256 ); would create the following situation:

O
O     C
O

to

O     C  
O
O

IMO, keeping the z of the camera aligned w/ the center of the exam (z=128) makes sense. But it is subjective.

Here follows the initial viewing angle for camera.position.set( 0, 0, 256 );:

image

Copy link
Contributor Author

@rlschuller rlschuller Oct 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I understood, any camera.position.set( x, y, z );, such that sqrt(x^2 + y^2 + (z-128)^2) is approx 1000 = half of the new distance for the frustrum's far plane will work fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can imagine it as a rotating table.

We don't want the camera to be just outside of the radius of the object:
image

But outside of the radius of the rotating table itself:
image

Copy link
Contributor Author

@rlschuller rlschuller Oct 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for camera.position.set( 0, 0, 256 );, small translations make the clipping appear again:

0_0_256

@WestLangley
Copy link
Collaborator

Make these temporary changes so you can see what is happening:

scene.add( new THREE.AxesHelper( 256 ) );

const mesh = new THREE.Mesh( geometry, new THREE.MeshNormalMaterial() );

Fix the clipping by moving the camera back a bit;

camera.position.set( - 64, - 64, 128 );

Then disable panning.

controls.enablePan = false;

@rlschuller
Copy link
Contributor Author

Thanks for the feedback and suggestions, AxesHelper did indeed live up to its name. Pretty cool.

Your library is awesome, and I'll definitely keep using it in the future. I'm new to Open Source contributions and PRs, so please let me know if I do (or am doing) something wrong, such a too much verbosity or things like that.

All of the translation and positioning functions are working exactly as expected and in agreement with the documentation. The center of the BoxGeometry is corectly beeing drawn at O = (63.5, 63.5, 127.5), w/ relevant lines shown bellow:

// THREE.Mesh
const geometry = new THREE.BoxGeometry( volume.xLength, volume.yLength, volume.zLength );
geometry.translate( volume.xLength / 2 - 0.5, volume.yLength / 2 - 0.5, volume.zLength / 2 - 0.5 );

Therefore, the suggestion

camera.position.set( - 64, - 64, 128 );

works fine when Pan is disabled, with initial point of view shown bellow:

image

To keep this point of view and also enable Pan, my suggestion would be to position the object in the center of the frustrum with the far plane 2000 units away and near plane 1 unit away, ie

camera.position.set( - 643, - 643, 128 );

Since, (a - 64)² + (a - 64)² = ((2000+1)/2)², for a < 0, yelds a ~ - 643 (or a ~ - 644 if we consider the fractional coordinates of O).

@WestLangley
Copy link
Collaborator

I would do what I recommended. You can't prevent clipping when the user is able to pan without limitation.

Disable pan, move camera to -64, -64, 128 and restore original frustum.
@rlschuller
Copy link
Contributor Author

I usually make the near and far clipping more lenient than the left and right clipping, for reasonable zoom levels and aspect ratios. If the users pan themselves to the moon, it's their fault. ;)

But you're probably right, this model isn't detailed enough to justify enabling Pan.

@mrdoob mrdoob added this to the r134 milestone Oct 8, 2021
@mrdoob mrdoob merged commit be3e3d2 into mrdoob:dev Oct 8, 2021
@mrdoob
Copy link
Owner

mrdoob commented Oct 8, 2021

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants