@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
154 lines (145 loc) • 4.57 kB
text/typescript
/**
* Populates informations from an IntersectData into its parameters
*
* @remarks
*
* This node typically works with the event/raycast
*
*/
import {TypedEventNode} from './_Base';
import {AttribType, ATTRIBUTE_TYPES, AttribTypeMenuEntries} from '../../../core/geometry/Constant';
import {EventConnectionPoint, EventConnectionPointType} from '../utils/io/connections/Event';
import {Intersection} from 'three';
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {isString, isNumber, isArray, isVector} from '../../../core/Type';
import {TypeAssert} from '../../poly/Assert';
import {resolveIntersectGeometryAttribute} from '../../../core/geometry/intersect/CoreIntersect';
import {coreObjectClassFactory} from '../../../core/geometry/CoreObjectFactory';
import {EventContext} from '../../../core/event/EventContextType';
export enum TargetType {
SCENE_GRAPH = 'scene graph',
NODE = 'node',
}
export const TARGET_TYPES: TargetType[] = [TargetType.SCENE_GRAPH, TargetType.NODE];
class IntersectDataParamsConfig extends NodeParamsConfig {
/** @param geometry vertex attribute to read */
attributeName = ParamConfig.STRING('id', {
cook: false,
});
/** @param type of attribute */
attributeType = ParamConfig.INTEGER(ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), {
menu: {
entries: AttribTypeMenuEntries,
},
});
/** @param attribute value for float */
attributeValue1 = ParamConfig.FLOAT(0, {
cook: false,
visibleIf: {
attributeType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC),
},
});
/** @param attribute value that attributeValue1 is set to when no object is intersected */
resetValue1 = ParamConfig.FLOAT(-1, {
cook: false,
visibleIf: {
attributeType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC),
},
});
/** @param attribute value for string */
attributeValues = ParamConfig.STRING('', {
visibleIf: {
attributeType: ATTRIBUTE_TYPES.indexOf(AttribType.STRING),
},
});
/** @param attribute value that attributeValues is set to when no object is intersected */
resetValues = ParamConfig.STRING('', {
visibleIf: {
attributeType: ATTRIBUTE_TYPES.indexOf(AttribType.STRING),
},
});
}
const ParamsConfig = new IntersectDataParamsConfig();
export class IntersectDataEventNode extends TypedEventNode<IntersectDataParamsConfig> {
override paramsConfig = ParamsConfig;
static override type() {
return 'intersectData';
}
static readonly INPUT_HIT = 'hit';
static readonly INPUT_MISS = 'miss';
override initializeNode() {
this.io.inputs.setNamedInputConnectionPoints([
new EventConnectionPoint(
IntersectDataEventNode.INPUT_HIT,
EventConnectionPointType.BASE,
this._processHit.bind(this)
),
new EventConnectionPoint(
IntersectDataEventNode.INPUT_MISS,
EventConnectionPointType.BASE,
this._processMiss.bind(this)
),
]);
}
private _processHit(context: EventContext<Event>) {
const intersect = context.value?.intersect;
if (!intersect) {
return;
}
this._resolveIntersectAttribute(intersect);
}
private _processMiss(context: EventContext<Event>) {
const attribType = ATTRIBUTE_TYPES[this.pv.attributeType];
switch (attribType) {
case AttribType.NUMERIC: {
this.p.attributeValue1.set(this.pv.resetValue1);
return;
}
case AttribType.STRING: {
this.p.attributeValues.set(this.pv.resetValues);
return;
}
}
TypeAssert.unreachable(attribType);
}
private _resolveIntersectAttribute(intersection: Intersection) {
const attribType = ATTRIBUTE_TYPES[this.pv.attributeType];
let attribValue: string | number | null | undefined = IntersectDataEventNode.resolveObjectAttribute(
intersection,
this.pv.attributeName
);
if (attribValue == null) {
attribValue = resolveIntersectGeometryAttribute(intersection, this.pv.attributeName, attribType);
}
if (attribValue != null) {
switch (attribType) {
case AttribType.NUMERIC: {
this.p.attributeValue1.set(attribValue);
return;
}
case AttribType.STRING: {
if (isString(attribValue)) {
this.p.attributeValues.set(attribValue);
}
return;
}
}
TypeAssert.unreachable(attribType);
}
}
static resolveObjectAttribute(intersection: Intersection, attribName: string) {
const value = coreObjectClassFactory(intersection.object).attribValue(intersection.object, attribName);
if (value == null) {
return;
}
if (isNumber(value) || isString(value)) {
return value;
}
if (isArray(value)) {
return value[0];
}
if (isVector(value)) {
return value.x;
}
}
}