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

Clipping Planes #6026

Merged
merged 78 commits into from
Dec 5, 2017
Merged

Clipping Planes #6026

merged 78 commits into from
Dec 5, 2017

Conversation

ggetz
Copy link
Contributor

@ggetz ggetz commented Dec 4, 2017

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.


if (vertexFormat.position &&
(vertexFormat.st || vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent)) {
if (vertexFormat.position) {
Copy link
Contributor

@hpinkos hpinkos Dec 7, 2017

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;
Copy link
Contributor

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);
Copy link
Contributor

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))
Copy link
Contributor

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);
Copy link
Contributor

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?

Copy link
Contributor Author

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);
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

@mramato
Copy link
Contributor

mramato commented Dec 7, 2017

@mramato do you have opinions on this?

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;
Copy link
Contributor

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.
Copy link
Contributor

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?

Copy link
Contributor Author

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.

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 have it at 6 for now because that's all the faces of a cube.

Copy link
Contributor

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));
Copy link
Contributor

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.

Copy link
Contributor

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) {
Copy link
Contributor

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.
Copy link
Contributor

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();
Copy link
Contributor

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

Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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;
Copy link
Contributor

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

Copy link
Contributor

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;
Copy link
Contributor

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;
Copy link
Contributor

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);
Copy link
Contributor

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) {
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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

@hpinkos
Copy link
Contributor

hpinkos commented Dec 7, 2017

@ggetz please open a new PR with these changes

@lilleyse for a PR with a new feature like this, please give other people on the team more time to review it before merging it in. This was only open for a day and I found a number of mistakes.

@lilleyse
Copy link
Contributor

lilleyse commented Dec 7, 2017

Thanks for the review, clearly I missed a lot of stuff. I'll keep it open longer next time.

@hpinkos
Copy link
Contributor

hpinkos commented Dec 7, 2017

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 : {
Copy link
Contributor

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.

@ggetz
Copy link
Contributor Author

ggetz commented Dec 7, 2017

Thanks @hpinkos ! I'll open a new PR for these changes.

@ggetz ggetz mentioned this pull request Dec 11, 2017
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.

5 participants