-
Notifications
You must be signed in to change notification settings - Fork 3.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
3D Tiles - Support vectors in the styling language #4759
Conversation
@@ -928,6 +1029,10 @@ define([ | |||
var right = this._right.evaluate(frameState, feature); | |||
if ((right instanceof Color) && (left instanceof Color)) { | |||
return Color.mod(left, right, ScratchStorage.getColor()); | |||
} else if ((right instanceof Cartesian4) && (left instanceof Cartesian4)) { | |||
// TODO : make mod a built-in Cartesian function? |
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.
Up to you, but I'm not sure it is worth it until/less we have another use case since we would also have to add it to Cartesian2
, Cartesian3
, etc.
The memory usage here is fine, but I am not thrilled with the potential compute overhead when evaluating expressions on the CPU. Perhaps don't worry about it now, but add a |
Since these look like GLSL types, can the spec please have a short section to explicitly say how the types are different than GLSL? For example, they do not support swizzling (and you'll have to decide if Also, does the GLSL implementation allow styles that are not valid, e.g., swizzling, since it is handed off to the GLSL compiler? If so, we should explicitly catch these cases. |
For the spec, what happens if the index is out of bounds when accessing the vector with array notation? |
expect(expression.evaluate(frameState, undefined)).toEqual(0.5); | ||
}); | ||
|
||
it('evaluates color properties (["red"], ["green"], ["blue"], ["alpha"])', function() { |
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.
What is the use case for supporting this? color[${CHANNEL}]
?
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 for color('yellow')['red']
equivalent to color('yellow').red
.
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.
Here and below, I see what it does, I'm just asking why since GLSL does not allow this since it does not have strings. How would the GLSL backend handle color[${CHANNEL}]
?
If there are compelling use cases, we can keep 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.
I'm just treating ["red"]
as a special case, but yeah other strings like color[${CHANNEL}]
will not work. I am fine with disallowing ["red"]
in GLSL for consistency.
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'm not sure what you mean by disallowing. I simply mean that arrays should be indexed with integers, not strings.
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.
Accessing color components like this is supported in the spec:
Bracket notation ([]) is also used to access properties, e.g., color['red'], or arrays, e.g., temperatures[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.
Ah, right. OK, disallow and document for now.
expect(expression.evaluate(frameState, undefined)).toEqual(0.5); | ||
}); | ||
|
||
it('evaluates color properties (["x"], ["y"], ["z"], ["w"])', function() { |
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.
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.
For vec4(1,1,1,1)['x']
equivalent to vec4(1,1,1,1).x
}); | ||
|
||
it('evaluates expression with multiple nested vectors', function() { | ||
var expression = new Expression('vec4(vec2(1, 2)[vec3(6, 1, 5).y], 2, vec4().w, 5)'); |
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.
Also for the spec, is construction like vec3(vec2(1.0, 2.0), 3.0)
allows? Up to you, just explicitly state 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.
This is not allowed, all components must evaluate to numbers (which the example above does). I will make this clear in the spec.
expression = new Expression('-vec3(1, 2, 3)'); | ||
expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(-1, -2, -3, 0)); | ||
|
||
expression = new Expression('vec2(1, 2) + vec4(3, 4, 5, 6)'); |
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.
Here and elsewhere, does GLSL allow this? I think this should be more strictly typed.
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.
GLSL does not allow it by default - but all vector types are turned into vec4 so this is valid. There are a lot of complications in recognizing vec2, vec3, vec4 type mismatches otherwise. I will add a note in the spec that vec2, vec3, and vec4 are just different constructors for the vector type - which is always vec4.
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 think you are letting this specific implementation too strongly influence the spec. Would a language really define that all vector types map to vec4
?
There are a lot of complications in recognizing vec2, vec3, vec4 type mismatches...
What are they?
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.
For the JS side it isn't too bad, just that operations between different Cartesian types will result in NaN. In GLSL the shader will not compile due to type mismatches (which cannot be verified ahead since properties are not known ... like color : ${id} > 10 ? vec3(1.0) : vec2(2.0)
).
Having everything be the same type makes it easier to do operations between vector properties and literal vectors without needing to support special constructors like vec4(${rgbcolor}, 1.0)
.
What about dropping vec2 and vec3 and always using vec4?
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.
What about dropping vec2 and vec3 and always using vec4?
We could see how much milage we get from this.
Remind me, why are we adding vector types at all right now? To flush out the math library with things like dot and cross products? If that is the case, don't we really need a vec3
.
I am also still not convinced that we can't reasonably detect this even if some error messages have to be "Could not compile generated GLSL shader, this is often due to a vector type mismatch."
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 vector types are needed to support vector properties in the batch table binary, which can be vec2, vec3, vec4, or accessing point positions with ${POSITION}
as well as math operations. Having vec4 as the base type also makes it easier to interact with colors (should colors and vectors mix?).
In line with other vector libraries I can support vec2, vec3, and vec4 as distinct types - however it will add more complexity.
Looks good, just those comments. |
This is allowed, but it will result in vec4(1,0,0,0) instead of vec4(1,1,1,1). I'll make it clear in the spec that unset components default to 0.
The GLSL implementation catches these cases and will throw a developer error.
Hm... good point - the current behavior is to return undefined in the JS backend and not compile in the GLSL backend. |
As I mentioned above, I don't think this is a good idea at the spec level.
Can we be consistent? Can variables be passed at runtime as array indices? If not, it is probably easy enough to catch this at compile time with GLSL and map |
Do you mean the spec should have it become
Yes variables can be passed at runtime so checking at compile-time is not possible. |
Yes, I would do vec4(1,1,1,1) like GLSL. The implicit mapping of all vector types to vec4 is just not at all common in the, I dunno, dozens of vector libraries I have seen. We should mirror GLSL as close as possible.
If the JavaScript and GLSL implementations need to be different, please record the details in CesiumGS/3d-tiles#140. We have to be very diligent and precise; otherwise, the styling ecosystem will not be robust. |
Sounds good to me. I'll follow GLSL more closely.
Added a note to the list. |
Update to support vec2, vec3, and vec4 as distinct types. The constructors follow the same rules as glsl, so some valid constructors are:
|
Do you want to move the tasklist in the first comment here to another roadmap? Merging this without finishing them is OK with me. |
// For example vec3(1, 2, 3) or vec3(vec2(1, 2), 3) are both valid. | ||
// | ||
// If the number of components does not equal the vector's size, then a DeveloperError is thrown - with two exceptions: | ||
// 1. A vector may be constructed from a larger vector and drop the extra components. |
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 (1) also true in GLSL?
If not, is it hard/slow to implement the same behavior here?
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.
Merging, we'll open a separate PR if this needs a code change.
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.
Yeah (1) is true in GLSL.
For CesiumGS/3d-tiles#2 and #3241
This adds support for vec2, vec3, and vec4 types in the styling language.
Under the hood all vector types are treated as
Cartesian4
, with missing components set to 0.0. Vector components may be accessed with .x, .y, .z, .w and [0], [1], [2], [3]. Colors components can also be accessed like this too in addition to .red, .green, .blue, and .alpha.The following operators are supported for vectors:
Unary +, unary -, +, - *, /, %, ===, ==, !==, !=
The following operators are not supported:
<, <, >=, <=, &&, ||, !~, =~
To-do: