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

3D Tiles - Ternary Functions (fixed) #4761

Merged
merged 4 commits into from
Dec 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Apps/Sandcastle/gallery/3D Tiles Point Cloud Styling.html
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@
pointSize : "5"
});

addStyle('Clamp and Mix', {
color : "color() * clamp(${temperature}, 0.1, 0.2)",
pointSize : "mix(${temperature}, 2.0, 0.5) * 0.2"
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Use some of the point cloud properties in here so that the point cloud is more dynamic looking. Also right now we technically don't support using clamp with anything but numbers (this will change soon).

Copy link
Contributor

Choose a reason for hiding this comment

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

It does translate to valid glsl code though by accident.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, what kind of properties should I be using? And should I remove clamp then?

Copy link
Contributor

Choose a reason for hiding this comment

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

Clamp is fine, I just mean to use the per-point properties temperature or id.

Copy link
Contributor

Choose a reason for hiding this comment

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

like clamp(${temperature}, 0.1, 0.2)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@lilleyse Done!

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah my mistake here, the shader doesn't compile because color: clamp(${temperature}, 0.1, 0.2) doesn't result in a color, but "color() * clamp(${temperature}, 0.1, 0.2)" should do the trick.

Can you also include temperature in the pointSize calculation.

Copy link
Contributor Author

@Dylan-Brown Dylan-Brown Dec 19, 2016

Choose a reason for hiding this comment

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

@lilleyse Also done! Also, I figured out that I can't run the Sandcastle app locally because in the Sandcastle folder, index.html refers to a few scripts that simply don't exist for me; it's easy to see using the javascript console in my chrome browser. So hopefully these adjustments work well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, I'm not sure why that's happening but the changes do look good.


addStyle('Secondary Color', {
color : {
expression : "[${secondaryColor}[0], ${secondaryColor}[1], ${secondaryColor}[2], 1.0]",
Expand Down
95 changes: 62 additions & 33 deletions Source/Scene/Expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ define([
degrees : CesiumMath.toDegrees
};

var ternaryFunctions = {
clamp : CesiumMath.clamp,
mix : CesiumMath.lerp
};

/**
* Evaluates an expression defined using the
* {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}.
Expand Down Expand Up @@ -379,21 +384,31 @@ define([
return new Node(ExpressionNodeType.UNARY, call);
} else if (defined(unaryFunctions[call])) {
//>>includeStart('debug', pragmas.debug);
if (args.length < 1 || args.length > 1) {
if (args.length !== 1) {
throw new DeveloperError('Error: ' + call + ' requires exactly one argument.');
}
//>>includeEnd('debug');
val = createRuntimeAst(expression, args[0]);
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (defined(binaryFunctions[call])) {
//>>includeStart('debug', pragmas.debug);
if (args.length < 2 || args.length > 2) {
if (args.length !== 2) {
throw new DeveloperError('Error: ' + call + ' requires exactly two arguments.');
}
//>>includeEnd('debug');
left = createRuntimeAst(expression, args[0]);
right = createRuntimeAst(expression, args[1]);
return new Node(ExpressionNodeType.BINARY, call, left, right);
} else if (defined(ternaryFunctions[call])) {
//>>includeStart('debug', pragmas.debug);
if (args.length !== 3) {
throw new DeveloperError('Error: ' + call + ' requires exactly three arguments.');
}
//>>includeEnd('debug');
left = createRuntimeAst(expression, args[0]);
right = createRuntimeAst(expression, args[1]);
var test = createRuntimeAst(expression, args[2]);
return new Node(ExpressionNodeType.TERNARY, call, left, right, test);
} else if (call === 'Boolean') {
if (args.length === 0) {
return new Node(ExpressionNodeType.LITERAL_BOOLEAN, false);
Expand Down Expand Up @@ -582,6 +597,32 @@ define([
} else if (node._value === 'toString') {
node.evaluate = node._evaluateToString;
}
} else if (node._type === ExpressionNodeType.UNARY) {
if (node._value === '!') {
node.evaluate = node._evaluateNot;
} else if (node._value === '-') {
node.evaluate = node._evaluateNegative;
} else if (node._value === '+') {
node.evaluate = node._evaluatePositive;
} else if (node._value === 'isNaN') {
node.evaluate = node._evaluateNaN;
} else if (node._value === 'isFinite') {
node.evaluate = node._evaluateIsFinite;
} else if (node._value === 'isExactClass') {
node.evaluate = node._evaluateIsExactClass;
} else if (node._value === 'isClass') {
node.evaluate = node._evaluateIsClass;
} else if (node._value === 'getExactClassName') {
node.evaluate = node._evaluategetExactClassName;
} else if (node._value === 'Boolean') {
node.evaluate = node._evaluateBooleanConversion;
} else if (node._value === 'Number') {
node.evaluate = node._evaluateNumberConversion;
} else if (node._value === 'String') {
node.evaluate = node._evaluateStringConversion;
} else if (defined(unaryFunctions[node._value])) {
node.evaluate = getEvaluateUnaryFunction(node._value);
}
} else if (node._type === ExpressionNodeType.BINARY) {
if (node._value === '+') {
node.evaluate = node._evaluatePlus;
Expand Down Expand Up @@ -620,32 +661,8 @@ define([
} else if (defined(binaryFunctions[node._value])) {
node.evaluate = getEvaluateBinaryFunction(node._value);
}
} else if (node._type === ExpressionNodeType.UNARY) {
if (node._value === '!') {
node.evaluate = node._evaluateNot;
} else if (node._value === '-') {
node.evaluate = node._evaluateNegative;
} else if (node._value === '+') {
node.evaluate = node._evaluatePositive;
} else if (node._value === 'isNaN') {
node.evaluate = node._evaluateNaN;
} else if (node._value === 'isFinite') {
node.evaluate = node._evaluateIsFinite;
} else if (node._value === 'isExactClass') {
node.evaluate = node._evaluateIsExactClass;
} else if (node._value === 'isClass') {
node.evaluate = node._evaluateIsClass;
} else if (node._value === 'getExactClassName') {
node.evaluate = node._evaluategetExactClassName;
} else if (defined(unaryFunctions[node._value])) {
node.evaluate = getEvaluateUnaryFunction(node._value);
} else if (node._value === 'Boolean') {
node.evaluate = node._evaluateBooleanConversion;
} else if (node._value === 'Number') {
node.evaluate = node._evaluateNumberConversion;
} else if (node._value === 'String') {
node.evaluate = node._evaluateStringConversion;
}
} else if (node._type === ExpressionNodeType.TERNARY) {
node.evaluate = getEvaluateTernaryFunction(node._value);
} else if (node._type === ExpressionNodeType.MEMBER) {
if (node._value === 'brackets') {
node.evaluate = node._evaluateMemberBrackets;
Expand Down Expand Up @@ -677,17 +694,24 @@ define([
return feature._content._tileset.timeSinceLoad;
}

function getEvaluateUnaryFunction(call) {
var evaluate = unaryFunctions[call];
return function(feature) {
return evaluate(this._left.evaluate(feature));
};
}

function getEvaluateBinaryFunction(call) {
var evaluate = binaryFunctions[call];
return function(feature) {
return evaluate(this._left.evaluate(feature), this._right.evaluate(feature));
};
}

function getEvaluateUnaryFunction(call) {
var evaluate = unaryFunctions[call];
function getEvaluateTernaryFunction(call) {
var evaluate = ternaryFunctions[call];
return function(feature) {
return evaluate(this._left.evaluate(feature));
return evaluate(this._left.evaluate(feature), this._right.evaluate(feature), this._test.evaluate(feature));
};
}

Expand Down Expand Up @@ -1217,14 +1241,14 @@ define([
return 'bool(' + left + ')';
} else if (value === 'Number') {
return 'float(' + left + ')';
} else if (defined(unaryFunctions[value])) {
return value + '(' + left + ')';
} else if (value === 'abs') {
return 'abs(' + left + ')';
} else if (value === 'cos') {
return 'cos(' + left + ')';
} else if (value === 'sqrt') {
return 'sqrt(' + left + ')';
} else if (defined(unaryFunctions[value])) {
return value + '(' + left + ')';
}
//>>includeStart('debug', pragmas.debug);
else if ((value === 'isNaN') || (value === 'isFinite') || (value === 'String') || (value === 'isExactClass') || (value === 'isClass') || (value === 'getExactClassName')) {
Expand All @@ -1246,6 +1270,11 @@ define([
return value + '(' + left + ', ' + right + ')';
}
return '(' + left + ' ' + value + ' ' + right + ')';
case ExpressionNodeType.TERNARY:
if (defined(ternaryFunctions[value])) {
return value + '(' + left + ', ' + right + ', ' + test + ')';
}
break;
case ExpressionNodeType.CONDITIONAL:
return '(' + test + ' ? ' + left + ' : ' + right + ')';
case ExpressionNodeType.MEMBER:
Expand Down
31 changes: 16 additions & 15 deletions Source/Scene/ExpressionNodeType.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*global define*/
define([
'../Core/freezeObject'
], function(
], function(
freezeObject) {
'use strict';

Expand All @@ -12,20 +12,21 @@ define([
VARIABLE : 0,
UNARY : 1,
BINARY : 2,
CONDITIONAL : 3,
MEMBER : 4,
FUNCTION_CALL : 5,
ARRAY : 6,
REGEX: 7,
VARIABLE_IN_STRING : 8,
LITERAL_NULL : 9,
LITERAL_BOOLEAN : 10,
LITERAL_NUMBER : 11,
LITERAL_STRING : 12,
LITERAL_COLOR : 13,
LITERAL_REGEX : 14,
LITERAL_UNDEFINED : 15,
LITERAL_GLOBAL : 16
TERNARY : 3,
CONDITIONAL : 4,
MEMBER : 5,
FUNCTION_CALL : 6,
ARRAY : 7,
REGEX: 8,
VARIABLE_IN_STRING : 9,
LITERAL_NULL : 10,
LITERAL_BOOLEAN : 11,
LITERAL_NUMBER : 12,
LITERAL_STRING : 13,
LITERAL_COLOR : 14,
LITERAL_REGEX : 15,
LITERAL_UNDEFINED : 16,
LITERAL_GLOBAL : 17
};

return freezeObject(ExpressionNodeType);
Expand Down
66 changes: 66 additions & 0 deletions Specs/Scene/ExpressionSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,58 @@ defineSuite([
}).toThrowDeveloperError();
});

it('evaluates clamp function', function() {
var expression = new Expression('clamp(50.0, 0.0, 100.0)');
expect(expression.evaluate(frameState, undefined)).toEqual(50.0);

expression = new Expression('clamp(50.0, 0.0, 25.0)');
expect(expression.evaluate(frameState, undefined)).toEqual(25.0);

expression = new Expression('clamp(50.0, 75.0, 100.0)');
expect(expression.evaluate(frameState, undefined)).toEqual(75.0);
});

it('throws if clamp function takes an invalid number of arguments', function() {
expect(function() {
return new Expression('clamp()');
}).toThrowDeveloperError();

expect(function() {
return new Expression('clamp(1)');
}).toThrowDeveloperError();

expect(function() {
return new Expression('clamp(1, 2)');
}).toThrowDeveloperError();

expect(function() {
return new Expression('clamp(1, 2, 3, 4)');
}).toThrowDeveloperError();
});

it('evaluates mix function', function() {
var expression = new Expression('mix(0.0, 2.0, 0.5)');
expect(expression.evaluate(frameState, undefined)).toEqual(1.0);
});

it('throws if mix function takes an invalid number of arguments', function() {
expect(function() {
return new Expression('mix()');
}).toThrowDeveloperError();

expect(function() {
return new Expression('mix(1)');
}).toThrowDeveloperError();

expect(function() {
return new Expression('mix(1, 2)');
}).toThrowDeveloperError();

expect(function() {
return new Expression('mix(1, 2, 3, 4)');
}).toThrowDeveloperError();
});

it('evaluates atan2 function', function() {
var expression = new Expression('atan2(0,1)');
expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(0.0, CesiumMath.EPSILON10);
Expand Down Expand Up @@ -1955,6 +2007,20 @@ defineSuite([
expect(shaderExpression).toEqual(expected);
});

it('gets shader expression for clamp', function() {
var expression = new Expression('clamp(50.0, 0.0, 100.0)');
var shaderExpression = expression.getShaderExpression('', {});
var expected = 'clamp(50.0, 0.0, 100.0)';
expect(shaderExpression).toEqual(expected);
});

it('gets shader expression for mix', function() {
var expression = new Expression('mix(0.0, 2.0, 0.5)');
var shaderExpression = expression.getShaderExpression('', {});
var expected = 'mix(0.0, 2.0, 0.5)';
expect(shaderExpression).toEqual(expected);
});

it('gets shader expression for atan2', function() {
var expression = new Expression('atan2(0.0,1.0)');
var shaderExpression = expression.getShaderExpression('', {});
Expand Down