-
-
Notifications
You must be signed in to change notification settings - Fork 35.3k
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
Compute ParametricGeometry normals from tangent vectors #11056
Conversation
src/geometries/ParametricGeometry.js
Outdated
// approximate tangent plane vectors via central difference | ||
|
||
pu.subVectors( func( u + EPS, v ), func( u - EPS, v ) ); | ||
pv.subVectors( func( u, v + EPS ), func( u, v - EPS ) ); |
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.
Should the Vector3
s returned by func
be .clone
ed here in case the Vector3
s actually reference the same object? Or is there a better way to do this?
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.
func
normally returns a new instance of Vector3
, see https://github.com/mrdoob/three.js/blob/dev/examples/js/ParametricGeometries.js
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.
@Mugen87 Actually, there should be no reason to instantiate 4 * slices * stacks
Vector3
's when using central differences. We could add an optionalTarget
to func()
and reuse just two instances.
var result = optionalTarget || new THREE.Vector3();
...
return result.set( x, y, z );
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.
Sounds reasonable. We can also adjust some entities in THREE.ParametricGeometries
so they use the optionalTarget
. But let's do this in a separate PR, okay?
@jaxry Are you interested in doing this 😉 ?
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.
Yes. Separate PR.
There is no need to override |
src/geometries/ParametricGeometry.js
Outdated
@@ -72,6 +77,16 @@ function ParametricBufferGeometry( func, slices, stacks ) { | |||
var p = func( u, v ); | |||
vertices.push( p.x, p.y, p.z ); | |||
|
|||
// approximate tangent plane vectors via central difference | |||
|
|||
pu.subVectors( func( u + EPS, v ), func( u - EPS, v ) ); |
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.
Is func( u, v )
guaranteed to be well-defined for values of u, v
outside [ 0, 1 ] ?
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 a good point! According to the implementation of func()
, values outside [ 0, 1 ] can be problematic.
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.
Then, use non-centered differences with a special case for the edge. By reusing p
, only two additional calls are needed.
src/geometries/ParametricGeometry.js
Outdated
|
||
// cross product of tangent plane vectors returns surface normal | ||
|
||
normal.crossVectors( pu, pv ); |
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.
normal.crossVectors( pu, pv ).normalize();
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.
👍
src/geometries/ParametricGeometry.js
Outdated
// generate normals | ||
|
||
this.computeVertexNormals(); | ||
this.normalizeNormals(); |
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.
not needed
Yes, This is a good change as long as |
Thanks for the feedback. I implemented your suggestions. |
Thanks! |
The ParametricGeometry class generates vertex normals as usual from the geometry's faces. However, this method leads to incorrectly computed normals for closed parametric surfaces. Where two ends of a surface meet, a seam is created since the positions along the edge are shared, but the indices of the geometry aren't.
For example, here you can see two seams on this torus created using ParametricGeometry:
This PR attempts to solve the problem. These seams are removed if you calculate the normals from the parametric equation itself.
By approximating tangent vectors for each vertex via the finite difference method and taking the cross product of the vectors, a correct surface normal is retrieved.
I have a few concerns about my code.
computeVertexNormals
method remains untouched, so if this method is called, the normals will be computed from the geometry faces again. The method could be overridden in ParametricGeometry and made to compute normals from the parametric equation, but the overridden method would contain a lot of duplicated code, since the method would still function very similarly. I'm not sure how to proceed.