-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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 #6026
Clipping Planes #6026
Conversation
Clipping planes for models, tilesets, point clouds
|
||
if (vertexFormat.position && | ||
(vertexFormat.st || vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent)) { | ||
if (vertexFormat.position) { |
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.
Won't this always be true? It's in the block for if (vertexFormat.position && ...)
positions[11] = 0.0; | ||
|
||
// -z face | ||
positions[12] = min.x; |
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 don't get why we need to create a front and back face. We don't do this for WallGeometry
. You just need to set the correct attributes for the appearance when you're creating the primitive so it doesn't do backface culling
}); | ||
|
||
// 12 triangles: 2 faces, 2 triangles each. | ||
indices = new Uint16Array(2 * 2 * 3); |
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.
This is wrong. We only have 1 face here with 2 triangles
attributes : attributes, | ||
indices : indices, | ||
primitiveType : PrimitiveType.LINES, | ||
boundingSphere : new BoundingSphere(Cartesian3.ZERO, Math.sqrt(2.0)) |
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.
The value for this bounding sphere is different than that for PlaneGeometry
. Which one is correct?
@@ -153,6 +153,7 @@ define([ | |||
model.color = Property.getValueOrDefault(modelGraphics._color, time, defaultColor, model._color); | |||
model.colorBlendMode = Property.getValueOrDefault(modelGraphics._colorBlendMode, time, defaultColorBlendMode); | |||
model.colorBlendAmount = Property.getValueOrDefault(modelGraphics._colorBlendAmount, time, defaultColorBlendAmount); | |||
model.clippingPlanes = Property.getValueOrUndefined(modelGraphics._clippingPlanes, time); |
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 this take a result parameter?
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 don't think so, it should just return undefined
if there's no value.
var vertexFormat = planeGeometry._vertexFormat; | ||
|
||
var min = new Cartesian3(-0.5, -0.5, 0.0); | ||
var max = new Cartesian3( 0.5, 0.5, 0.0); |
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.
Since these are always the same we can move then out of this function scope
* @returns {Geometry|undefined} The computed vertices and indices. | ||
*/ | ||
PlaneOutlineGeometry.createGeometry = function() { | ||
var min = new Cartesian3(-0.5, -0.5, 0.0); |
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.
Ditto
} | ||
|
||
if (!defined(dimensions)) { | ||
dimensions = new Cartesian2(1.0, 1.0); |
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.
Can we use a scratch variable for this?
if (defined(clippingPlanes) && clippingPlanes.enabled) { | ||
var tileTransform = tileset._root.computedTransform; | ||
var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileTransform); | ||
this._isClipped = (intersection !== Intersect.INSIDE); |
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.
You don't need the ( )
if (defined(clippingPlanes) && clippingPlanes.enabled) { | ||
var tileTransform = tileset._root.computedTransform; | ||
var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileTransform); | ||
this._isClipped = (intersection !== Intersect.INSIDE); |
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.
ditto
I've only barely looked over the code here, but yes; it should be consistent with the rest of our API and the way it's currently set up is definitely not the way to go. |
* | ||
* @type {ClippingPlanesCollection} | ||
*/ | ||
this.clippingPlanes = options.clippingPlanes; |
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.
BUG: I set this value to a ClippingPlaneCollection
and it worked correctly. Then I set this value to undefined
but the tileset was still clipped
options = defaultValue(options, defaultValue.EMPTY_OBJECT); | ||
|
||
/** | ||
* An array of up to 6 {@link Plane} objects used to selectively disable rendering on the outside of each plane. |
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.
Why 6? What happens if you add more? Should we throw a developer error when someone tries to do that?
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.
This is an arbitrary limit we have based on the uniform we pass to the shader. We'd like to include more, but need to restructure how we pass in the planes, see the roadmap. If set to more, they are simply ignored.
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.
We have it at 6 for now because that's all the faces of a cube.
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.
Okay, that makes sense. I think we want to have this class follow the same API as the other XXXCollection
classes, so make this.planes
-> this._planes
, then in the constructor and the ClippingPlanesCollection.prototype.add
function throw a developer error if the length is greater than 6. That way people using clipping planes will be aware of what's going on instead of wondering why their planes were ignored
* @type {Matrix4} | ||
* @default Matrix4.IDENTITY | ||
*/ | ||
this.modelMatrix = defaultValue(options.modelMatrix, Matrix4.clone(Matrix4.IDENTITY)); |
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.
This should be Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY))
instead. Or do it in an if statement. Using defaultValue
makes the Matrxi4.clone
resolve first so we're creating a new Matrix4
every time regardless of whether or not we're using it.
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.
Same comment for edgeColor
below
|
||
function getTestIntersectionFunction(combineClippingRegions) { | ||
if (combineClippingRegions) { | ||
return function(value) { |
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.
This creates a new function each time this is called. Move these outside of the scope instead.
* Applies the transformations to each plane and packs it into an array. | ||
* @private | ||
* | ||
* @param viewMatrix The 4x4 matrix to transform the plane into eyespace. |
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.
param types?
array = new Array(length); | ||
|
||
for (i = 0; i < length; ++i) { | ||
array[i] = new Cartesian4(); |
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.
We can be smarter about this. You can assume that the result array is already filled with Cartesian4
right? So we only need to create new ones for the range i = oldArrayLength.length; i < length; i++
If the array passed in is too large, we can simply do array.length = length
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.
Why are we using a Cartesian4
anyway? Wouldn't it be better just to use a flat array where every 4 indices is equal to 1 plane?
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.
You can assume that the result array is already filled with Cartesian4 right?
We changed to this because it's a public method, and the result parameter is optional like our other methods that take result paramters. We can require it though if that's ok.
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.
It's alright if the result parameter is optional. But if a result parameter is supplied, we should be able to assume [0..length] is already filled with Cartesian4
so we don't need to make a new one for those indices
var plane = this.planes[i]; | ||
var resultPlane = result.planes[i]; | ||
resultPlane.normal = plane.normal; | ||
resultPlane.distance = plane.distance; |
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.
Let's add a clone
function to Plane
to handle 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.
You'll want to clone plane.normal
as well
@@ -80,6 +80,7 @@ define([ | |||
this.pickTerrain = undefined; | |||
|
|||
this.surfaceShader = undefined; | |||
this.isClipped = true; |
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.
It seems like this should default to false
or undefined
instead of true.
var planeIntersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume); | ||
tile.isClipped = (planeIntersection !== Intersect.INSIDE); | ||
if (planeIntersection === Intersect.OUTSIDE) { | ||
return Intersect.OUTSIDE; |
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.
The doc for this function says it returns a Visibility
so this return value doesn't seem correct
var length = this.planes.length; | ||
var i; | ||
if (result.planes.length !== length) { | ||
result.planes = new Array(length); |
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.
Same comment I made for ClippingPlanesCollection.transformAndPackPlanes
} | ||
|
||
var clippingPlanesProperty = uniformMapProperties.clippingPlanes; | ||
if (length !== clippingPlanesProperty.length) { |
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.
Same comment I made for ClippingPlanesCollection.transformAndPackPlanes
} | ||
|
||
if (model._packedClippingPlanes.length !== length) { | ||
model._packedClippingPlanes = new Array(length); |
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.
Same comment I made for ClippingPlanesCollection.transformAndPackPlanes
} | ||
|
||
if (this._packedClippingPlanes.length !== length) { | ||
this._packedClippingPlanes = new Array(length); |
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.
Same comment I made for ClippingPlanesCollection.transformAndPackPlanes
Thanks for the review, clearly I missed a lot of stuff. I'll keep it open longer next time. |
BUG: I zoomed into a point cloud until some of the higher resolution tiles started popping in. Then I added a clipping plane. Then I zoomed out and the lower resolution tiles were not clipped |
* @type {Boolean} | ||
* @default true | ||
*/ | ||
combineClippingRegions : { |
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 found the name of this property to be a little confusing and thought it did the opposite of what it actually does at first. It's essentially either doing a union
or an intersection
of the regions, right? The regions are more or less combined either way. I would rename it to unionClippingRegions
or something along those lines instead.
Thanks @hpinkos ! I'll open a new PR for these changes. |
Part of #5765
Code changes from #5996 (comment), and merged in master and updated
CHANGES.md
.@lilleyse This is my fork, we'll still need to delete the other
clip-planes-master
branch.