@openhps/core
Version:
Open Hybrid Positioning System - Core component
201 lines (192 loc) • 7.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.hardwareClipping = exports.default = exports.clippingAlpha = exports.clipping = void 0;
var _Node = _interopRequireDefault(require("../core/Node.js"));
var _TSLBase = require("../tsl/TSLBase.js");
var _Position = require("./Position.js");
var _PropertyNode = require("../core/PropertyNode.js");
var _LoopNode = require("../utils/LoopNode.js");
var _MathNode = require("../math/MathNode.js");
var _UniformArrayNode = require("./UniformArrayNode.js");
var _BuiltinNode = require("./BuiltinNode.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* This node is used in {@link NodeMaterial} to setup the clipping
* which can happen hardware-accelerated (if supported) and optionally
* use alpha-to-coverage for anti-aliasing clipped edges.
*
* @augments Node
*/
class ClippingNode extends _Node.default {
static get type() {
return 'ClippingNode';
}
/**
* Constructs a new clipping node.
*
* @param {('default'|'hardware'|'alphaToCoverage')} [scope='default'] - The node's scope. Similar to other nodes,
* the selected scope influences the behavior of the node and what type of code is generated.
*/
constructor(scope = ClippingNode.DEFAULT) {
super();
/**
* The node's scope. Similar to other nodes, the selected scope influences
* the behavior of the node and what type of code is generated.
*
* @type {('default'|'hardware'|'alphaToCoverage')}
*/
this.scope = scope;
}
/**
* Setups the node depending on the selected scope.
*
* @param {NodeBuilder} builder - The current node builder.
* @return {Node} The result node.
*/
setup(builder) {
super.setup(builder);
const clippingContext = builder.clippingContext;
const {
intersectionPlanes,
unionPlanes
} = clippingContext;
this.hardwareClipping = builder.material.hardwareClipping;
if (this.scope === ClippingNode.ALPHA_TO_COVERAGE) {
return this.setupAlphaToCoverage(intersectionPlanes, unionPlanes);
} else if (this.scope === ClippingNode.HARDWARE) {
return this.setupHardwareClipping(unionPlanes, builder);
} else {
return this.setupDefault(intersectionPlanes, unionPlanes);
}
}
/**
* Setups alpha to coverage.
*
* @param {Array<Vector4>} intersectionPlanes - The intersection planes.
* @param {Array<Vector4>} unionPlanes - The union planes.
* @return {Node} The result node.
*/
setupAlphaToCoverage(intersectionPlanes, unionPlanes) {
return (0, _TSLBase.Fn)(() => {
const distanceToPlane = (0, _TSLBase.float)().toVar('distanceToPlane');
const distanceGradient = (0, _TSLBase.float)().toVar('distanceToGradient');
const clipOpacity = (0, _TSLBase.float)(1).toVar('clipOpacity');
const numUnionPlanes = unionPlanes.length;
if (this.hardwareClipping === false && numUnionPlanes > 0) {
const clippingPlanes = (0, _UniformArrayNode.uniformArray)(unionPlanes);
(0, _LoopNode.Loop)(numUnionPlanes, ({
i
}) => {
const plane = clippingPlanes.element(i);
distanceToPlane.assign(_Position.positionView.dot(plane.xyz).negate().add(plane.w));
distanceGradient.assign(distanceToPlane.fwidth().div(2.0));
clipOpacity.mulAssign((0, _MathNode.smoothstep)(distanceGradient.negate(), distanceGradient, distanceToPlane));
});
}
const numIntersectionPlanes = intersectionPlanes.length;
if (numIntersectionPlanes > 0) {
const clippingPlanes = (0, _UniformArrayNode.uniformArray)(intersectionPlanes);
const intersectionClipOpacity = (0, _TSLBase.float)(1).toVar('intersectionClipOpacity');
(0, _LoopNode.Loop)(numIntersectionPlanes, ({
i
}) => {
const plane = clippingPlanes.element(i);
distanceToPlane.assign(_Position.positionView.dot(plane.xyz).negate().add(plane.w));
distanceGradient.assign(distanceToPlane.fwidth().div(2.0));
intersectionClipOpacity.mulAssign((0, _MathNode.smoothstep)(distanceGradient.negate(), distanceGradient, distanceToPlane).oneMinus());
});
clipOpacity.mulAssign(intersectionClipOpacity.oneMinus());
}
_PropertyNode.diffuseColor.a.mulAssign(clipOpacity);
_PropertyNode.diffuseColor.a.equal(0.0).discard();
})();
}
/**
* Setups the default clipping.
*
* @param {Array<Vector4>} intersectionPlanes - The intersection planes.
* @param {Array<Vector4>} unionPlanes - The union planes.
* @return {Node} The result node.
*/
setupDefault(intersectionPlanes, unionPlanes) {
return (0, _TSLBase.Fn)(() => {
const numUnionPlanes = unionPlanes.length;
if (this.hardwareClipping === false && numUnionPlanes > 0) {
const clippingPlanes = (0, _UniformArrayNode.uniformArray)(unionPlanes);
(0, _LoopNode.Loop)(numUnionPlanes, ({
i
}) => {
const plane = clippingPlanes.element(i);
_Position.positionView.dot(plane.xyz).greaterThan(plane.w).discard();
});
}
const numIntersectionPlanes = intersectionPlanes.length;
if (numIntersectionPlanes > 0) {
const clippingPlanes = (0, _UniformArrayNode.uniformArray)(intersectionPlanes);
const clipped = (0, _TSLBase.bool)(true).toVar('clipped');
(0, _LoopNode.Loop)(numIntersectionPlanes, ({
i
}) => {
const plane = clippingPlanes.element(i);
clipped.assign(_Position.positionView.dot(plane.xyz).greaterThan(plane.w).and(clipped));
});
clipped.discard();
}
})();
}
/**
* Setups hardware clipping.
*
* @param {Array<Vector4>} unionPlanes - The union planes.
* @param {NodeBuilder} builder - The current node builder.
* @return {Node} The result node.
*/
setupHardwareClipping(unionPlanes, builder) {
const numUnionPlanes = unionPlanes.length;
builder.enableHardwareClipping(numUnionPlanes);
return (0, _TSLBase.Fn)(() => {
const clippingPlanes = (0, _UniformArrayNode.uniformArray)(unionPlanes);
const hw_clip_distances = (0, _BuiltinNode.builtin)(builder.getClipDistance());
(0, _LoopNode.Loop)(numUnionPlanes, ({
i
}) => {
const plane = clippingPlanes.element(i);
const distance = _Position.positionView.dot(plane.xyz).sub(plane.w).negate();
hw_clip_distances.element(i).assign(distance);
});
})();
}
}
ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage';
ClippingNode.DEFAULT = 'default';
ClippingNode.HARDWARE = 'hardware';
var _default = exports.default = ClippingNode;
/**
* TSL function for setting up the default clipping logic.
*
* @tsl
* @function
* @returns {ClippingNode}
*/
const clipping = () => (0, _TSLBase.nodeObject)(new ClippingNode());
/**
* TSL function for setting up alpha to coverage.
*
* @tsl
* @function
* @returns {ClippingNode}
*/
exports.clipping = clipping;
const clippingAlpha = () => (0, _TSLBase.nodeObject)(new ClippingNode(ClippingNode.ALPHA_TO_COVERAGE));
/**
* TSL function for setting up hardware-based clipping.
*
* @tsl
* @function
* @returns {ClippingNode}
*/
exports.clippingAlpha = clippingAlpha;
const hardwareClipping = () => (0, _TSLBase.nodeObject)(new ClippingNode(ClippingNode.HARDWARE));
exports.hardwareClipping = hardwareClipping;